处理(在 python 中)IOError 的正确方法是什么:[Errno 4] Interrupted system call,由 multiprocessing.Queue.get 引发

问题描述

当我使用 multiprocessing.Queue.get 时,有时由于 EINTR 会出现异常.

When I use multiprocessing.Queue.get I sometimes get an exception due to EINTR.

我清楚地知道,有时这种情况会无缘无故地发生(我在 tmux 缓冲区中打开另一个窗格),在这种情况下,我想继续工作并重试该操作.

I know definitely that sometimes this happens for no good reason (I open another pane in a tmux buffr), and in such a case I would want to continue working and retry the operation.

我可以想象,在某些其他情况下,错误是有充分理由的,我应该停止运行或修复一些错误.

I can imagine that in some other cases The error would be due to a good reason and I should stop running or fix some error.

如何区分两者?

提前致谢


解决方案

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

The EINTR error can be returned from many system calls when the application receives a signal while waiting for other input. Typically these signals can be quite benign and already handled by Python, but the underlying system call still ends up being interrupted. When doing C/C++ coding this is one reason why you can't entirely rely on functions like sleep(). The Python libraries sometimes handle this error code internally, but obviously in this case they're not.

您可能有兴趣阅读 此线程 讨论了这个问题.

You might be interested to read this thread which discusses this problem.

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

The general approach to EINTR is to simply handle the error and retry the operation again - this should be a safe thing to do with the get() method on the queue. Something like this could be used, passing the queue as a parameter and replacing the use of the get() method on the queue:

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.

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

Typically you shouldn't need to worry about EINTR in a Python program unless you know you're waiting for a particular signal (for example SIGHUP) and you've installed a signal handler which sets a flag and relies on the main body of the code to pick up the flag. In this case, you might need to break out of your loop and check the signal flag if you receive EINTR.

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

However, if you're not using any signal handling then you should be able to just ignore EINTR and repeat your operation - if Python itself needs to do something with the signal it should have already dealt with it in the signal handler.

相关文章