【问题标题】:Python: Do I need to catch EINTR in a pipe-reading loopPython:我是否需要在管道读取循环中捕获 EINTR
【发布时间】:2014-03-13 17:58:01
【问题描述】:

tl;博士

在 Python 中读取管道时是否应该处理 EINTR“系统调用中断”错误,如果是,我该如何测试此类代码?

说明

在下面的回溯中,self._dataqmultiprocessing.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


    【解决方案1】:

    Python 3.5 通过将处理EINTR 的责任放在 Python 运行时而不是应用程序代码上来解决这个问题。请参阅PEP 475Python 3.5 Changelog

    【讨论】:

      【解决方案2】:

      我将把它称为 Python 中的错误。我找不到任何允许multiprocessing.QueueEINTR 上提出IOError 的文档(尽管提出其他I/O 问题是有意义的,这就是为什么你应该检查errno忽略它之前引发的异常的属性;请参阅errno),并且它不直接映射到任何提供此类行为的低级 C 函数。 some discussion 在 C 级别处理所有 EINTRs,但这并没有进入 3.4(我怀疑它是否会进入 2.x),所以这可能仍然是公平的游戏报告。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2010-11-02
        • 1970-01-01
        • 1970-01-01
        • 2018-11-15
        • 2011-11-10
        • 1970-01-01
        • 2015-07-13
        相关资源
        最近更新 更多