【发布时间】:2014-03-13 17:58:01
【问题描述】:
tl;博士
在 Python 中读取管道时是否应该处理 EINTR“系统调用中断”错误,如果是,我该如何测试此类代码?
说明
在下面的回溯中,self._dataq 是multiprocessing.Queue(技术上,我使用的是billiard 库,但我认为它们基本上是相同的代码)。 Python 子进程偶尔会写入队列的另一端。我认为发生的事情是一个系统调用正在读取为队列提供数据的管道,并且一个信号到达——可能是来自第二个 Ctrl+C 事件的 SIGINT(第一个 SIGINT 发生在你在第二个看到用户的 ^C日志输出的行,并且我的信号处理程序捕获了该 SIGINT,如您在日志中的 WARNING 消息中所见)。
[INFO 2014-03-05 14:16:06,000] Doing some work, la-dee-da
^C[WARNING 2014-03-05 14:16:07,344] Commencing shutdown. (Signal SIGINT, process 2469.). Press Ctrl+C again to exit immediately.
[DEBUG 2014-03-05 14:16:07,347] Terminating subprocess
Traceback (most recent call last):
[... a bunch of stuff omitted]
File "mycode.py", line 97, in __next__
result = self._dataq.get(timeout=0.1)
File "/usr/local/lib/python2.7/site-packages/billiard/queues.py", line 103, in get
if timeout < 0 or not self._poll(timeout):
IOError: [Errno 4] Interrupted system call
上述回溯中的语句result = self._dataq.get(timeout=0.1) 位于循环的中间,如下所示。循环的主要目的是,当self.timedout() 开始返回True 时,我可以放弃尝试从self._dataq 读取。
import queue
while True:
try:
result = self._dataq.get(timeout=0.1)
except queue.Empty:
if self.timedout():
self.close()
raise MyTimedoutError()
else:
break
问题
如果我关于IOError 发生原因的理论是正确的,那么上面的try...except 块应该在IOErrors 由中断的系统调用引起时捕获并忽略它们。如果它是导致 EINTR 错误的信号,那么仅仅回到 Python 中运行 except IOError: 语句的行为将允许 Python 级别的信号处理程序运行。
正确吗?如果是这样,是否可以在我的代码中测试此更改?对我来说,如何编写不包含严重竞争条件的单元测试并不明显。
【问题讨论】:
标签: python multiprocessing pipe system-calls eintr