从损坏的管道读取时,管道 Python 脚本占用 100% 的 CPU
Posted
技术标签:
【中文标题】从损坏的管道读取时,管道 Python 脚本占用 100% 的 CPU【英文标题】:Piped Python script takes 100% of CPU when reading from broken pipe 【发布时间】:2012-09-10 16:58:21 【问题描述】:我有两个 Python 脚本在 Ubuntu Linux 机器上运行。第一个将其所有输出发送到标准输出,第二个从标准输入读取。它们通过一个简单的管道连接,例如:
./step1.py <some_args> | ./step2.py <some_other_args>
step2 的作用是在无限循环中读取输入行并对其进行处理:
while True:
try:
l = sys.stdin.readline()
# processing here
Step1 时常崩溃。当这种情况发生时(不确定是否总是,但至少在几次情况下)不是崩溃/停止,而是 step2 变得疯狂并开始占用 100% 的 CPU,直到我手动杀死它。
为什么会发生这种情况?如何使 step2 更健壮,以便在管道损坏时停止?
谢谢!
【问题讨论】:
因为如果管道发生故障,您基本上拥有while True:pass
,它将垄断cpu add 和except: break;
以退出循环......或except:time.sleep(100)
或减轻负载的东西
你发现了什么异常?
【参考方案1】:
其他人已经解释了为什么在某些情况下你会陷入无限循环。
在第二个(阅读)脚本中,可以使用成语:
for line in sys.stdin:
process(line)
这样您就不会陷入无限循环。此外,您实际上并没有在第二个脚本中显示您尝试捕获的异常,但我猜您会不时遇到“破管”错误,您可以并且应该捕获如此处所述:How to handle a broken pipe (SIGPIPE) in python?
整个方案可能如下所示:
try:
for line in sys.stdin:
process(line)
except IOError, e:
if e.errno == errno.EPIPE:
# EPIPE error
else:
# Other error
【讨论】:
【参考方案2】:当 step1 终止时,您有一个 while 循环,其中包含一个 try 语句,该语句将引发异常。因此,您将使用 100% 的 CPU 不断尝试并失败,因为 readline 在抛出异常时不会阻塞。
要么使用time.sleep
为读取添加时间延迟,或者更好的是,注意 readline 抛出的错误并捕获当 step1 停止并退出程序而不是尝试从死机读取时抛出的特定错误管道。
您可能需要在管道为空时使用睡眠操作符,并在管道死亡时退出,但是在每种情况下都会抛出哪个异常以及什么消息,我将作为练习留给您确定。在这种情况下,睡眠运算符不是必需的,但它可以避免在无用工作上导致 CPU 使用率过高的其他情况。
【讨论】:
以上是关于从损坏的管道读取时,管道 Python 脚本占用 100% 的 CPU的主要内容,如果未能解决你的问题,请参考以下文章
带有标准输入的 subprocess.Popen.communicate() 的管道损坏
从命名管道、C 程序(编写器)和 Python(读取器)获取额外数据