我正在使用此命令从命名管道读取连续数据:
{ while :; do dd iflag=fullblock iflag=nonblock bs=65536 count=1 2> /dev/null | redis-cli -x PUBLISH myChannel ; done } < myFifo
问题是,即使我同时运行 50 个命令,CPU 使用率也会非常高。该进程应该长时间运行,并且许多命令应该同时运行。
那么,原因是什么?如何预防?谢谢。
答案1
如果我没记错的话,您是dd
为了缓冲目的而使用的...在您的情况下可能不需要循环...dd
将继续读取并输入指定大小的数据块,如果你不设置count
(这指示dd
在完成指定数量的读/写后退出) 或者iflag=nonblock
(你会想要阻塞 I/O成功启动读取并继续从命名管道读取dd
)并像这样使用它:
dd if=myFifo iflag=fullblock bs=65536 2> /dev/null | redis-cli -x PUBLISH myChannel
在这种情况下,只有到达输入文件的末尾时才应该退出(例如当命名管道的写入者终止/关闭管道时)。
或者为了保持管道始终打开并等待写入,请像这样使用:
tail -c +1 -F myFifo | dd iflag=fullblock bs=65536 2> /dev/null | redis-cli -x PUBLISH myChannel
或者如果你的应用程序期望流/管道结束(例如EOF
或close_write
...这不是流媒体应用程序的最佳选择), 使用GNU并行而是像这样:
tail -c +1 -F myFifo | parallel --max-procs 1 -P 1 -j 1 --pipe --block 64k -k 'redis-cli -x PUBLISH myChannel'
这应该类似于你的循环,但仅在你需要它的地方...它将以一种相当受控和资源感知的方式执行此操作...它还应该保持命名管道即使在写入之间也始终打开,保留流的每一位并缩短管道。
答案2
这while :
正在消耗你的 CPU。任何循环中的命令while :;
将导致 CPU 使用率过高。例如:
while :; do echo foo > /dev/null; done
或者,更明显的是,无操作:
while :; do true; done
您运行的命令几乎无关紧要:如果命令本身不需要花费太多时间,那么将while
导致高 CPU 使用率。这while :
意味着循环将在命令结束后立即重新启动,一遍又一遍。而且由于这dd
将几乎立即完成,这意味着它会一遍又一遍地启动,每秒多次,因此占用大量 CPU。
解决方案是在调用之间添加一个短暂的暂停:
{
while :; do
dd iflag=fullblock iflag=nonblock bs=65536 count=1 2> /dev/null |
redis-cli -x PUBLISH myChannel
sleep 0.1
done
} < myFifo
在运行之间添加哪怕 0.1 秒的休眠时间都可以避免占用过多的 CPU。