当我使用 multiprocessing.Queue.get 时,有时由于 EINTR 会出现异常。
我肯定知道有时这种情况没有充分的理由发生(我在 tmux 缓冲区中打开另一个窗格),在这种情况下,我想继续工作并重试该操作。
我可以想象,在其他一些情况下,错误是有充分理由的,我应该停止运行或修复一些错误。
我怎样才能区分这两者?
提前致谢
当我使用 multiprocessing.Queue.get 时,有时由于 EINTR 会出现异常。
我肯定知道有时这种情况没有充分的理由发生(我在 tmux 缓冲区中打开另一个窗格),在这种情况下,我想继续工作并重试该操作。
我可以想象,在其他一些情况下,错误是有充分理由的,我应该停止运行或修复一些错误。
我怎样才能区分这两者?
提前致谢
当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.
通常你不需要担心EINTR
Python 程序,除非你知道你正在等待一个特定的信号(例如SIGHUP
)并且你已经安装了一个信号处理程序,它设置一个标志并依赖于代码的主体来拿起旗帜。在这种情况下,您可能需要跳出循环并检查信号标志(如果收到EINTR
.
但是,如果您没有使用任何信号处理,那么您应该能够忽略EINTR
并重复您的操作 - 如果 Python 本身需要对信号做一些事情,它应该已经在信号处理程序中处理了它。
老问题,现代解决方案:从 Python 3.5 开始,精彩的PEP 475 - Retry system calls failed with EINTR已经实现并为您解决了问题。这是摘要:
标准库中提供的系统调用包装器应在失败时自动重试
EINTR
,以减轻应用程序代码这样做的负担。系统调用是指标准 C 库公开的与 I/O 或其他系统资源处理有关的函数。
基本上,系统会为你捕获并重试一段失败的代码,EINTR
这样你就不必再处理它了。如果您的目标是较旧的版本,那么while True
循环仍然是要走的路。但是请注意,如果您使用的是 Python 3.3 或 3.4,则可以捕获专用异常InterruptedError
,而不是捕获IOError
和检查EINTR
.