什么是正确的处理方式(在python中)IOError:[Errno 4]由多处理引发的系统调用中断.Queue.get

Shw*_*chk 13 python queue error-handling multiprocessing ioerror

当我使用multiprocessing.Queue.get时,由于EINTR,我有时会得到一个异常.

我肯定知道有时这种情况没有任何理由(我在tmux buffr中打开另一个窗格),在这种情况下我想继续工作并重试该操作.

我可以想象,在其他一些情况下,错误是由于一个很好的理由,我应该停止运行或修复一些错误.

我该如何区分这两者?

提前致谢

Car*_*roo 15

EINTR当应用程序接收的信号,同时等待其他输入可以从许多系统中返回的错误呼叫.通常这些信号可能非常温和并且已经由Python处理,但底层系统调用仍然最终被中断.在进行C/C++编码时,这就是为什么你不能完全依赖像这样的函数的原因之一sleep().Python库有时会在内部处理这个错误代码,但显然在这种情况下它们不是.

您可能有兴趣阅读讨论此问题的此主题.

一般的方法EINTR是简单地处理错误并再次重试操作 - 这get()对于队列上的方法应该是安全的.可以使用类似这样的东西,将队列作为参数传递并替换get()队列上方法的使用:

import errno

def my_queue_get(queue, block=True, timeout=None):
    while True:
        try:
            return queue.get(block, timeout)
        except IOError, e:
            if e.errno != errno.EINTR:
                raise

# Now replace instances of queue.get() with my_queue_get(queue), with other
# parameters passed as usual.
Run Code Online (Sandbox Code Playgroud)

通常你不必EINTR在Python程序中担心,除非你知道你正在等待一个特定的信号(例如SIGHUP)并且你已经安装了一个信号处理程序,它设置一个标志并依赖于代码的主体来拿起国旗.在这种情况下,您可能需要突破循环并检查信号标志(如果收到)EINTR.

但是,如果您没有使用任何信号处理,那么您应该能够忽略EINTR并重复您的操作 - 如果Python本身需要对信号执行某些操作,它应该已经在信号处理程序中处理它.


Mor*_*enn 6

旧问题,现代解决方案:从Python 3.5开始,精彩的PEP 475 - 重试系统调用失败并使用EINTR已经实现并为您解决问题.这是摘要:

标准库中提供的系统调用包装器应在失败时自动重试EINTR,以减轻应用程序代码的负担.

通过系统调用,我们指的是标准C库公开的与I/O或其他系统资源处理有关的函数.

基本上,系统会捕获并重试一段失败的代码,EINTR因此您不必再处理它.如果您的目标是旧版本,那么while True循环仍然是可行的方法.但请注意,如果您使用的是Python 3.3或3.4,则可以捕获专用异常,InterruptedError而不是捕获IOError和检查EINTR.