运行 dd 命令的 while 循环会导致 CPU 使用率过高

运行 dd 命令的 while 循环会导致 CPU 使用率过高

我正在使用此命令从命名管道读取连续数据:

{ 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

或者如果你的应用程序期望流/管道结束(例如EOFclose_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。

相关内容