【发布时间】:2012-04-23 15:31:40
【问题描述】:
尝试从 Cygwin 的多处理模块创建队列时遇到奇怪的间歇性错误:
Traceback (most recent call last):
File "test.py", line 3, in <module>
multiprocessing.Queue()
File "/usr/lib/python2.6/multiprocessing/__init__.py", line 213, in Queue
return Queue(maxsize)
File "/usr/lib/python2.6/multiprocessing/queues.py", line 37, in __init__
self._rlock = Lock()
File "/usr/lib/python2.6/multiprocessing/synchronize.py", line 117, in __init__
SemLock.__init__(self, SEMAPHORE, 1, 1)
File "/usr/lib/python2.6/multiprocessing/synchronize.py", line 49, in __init__
sl = self._semlock = _multiprocessing.SemLock(kind, value, maxvalue)
OSError: [Errno 17] File exists
重现这个的最少代码就是:
import multiprocessing
multiprocessing.Queue()
虽然错误只发生大约 25% 的时间。
目前为了“解决”这个问题,我只有一个 while 循环,它不断创建 Queues 直到错误没有出现,但我宁愿弄清楚它为什么会发生。我尝试查看记录的源文件,但即使一直追溯到 c 源也没有发现任何线索。
我在 Windows 7 64 位上运行来自 Cygwin 的 python 2.6.7。如果我通过本机 windows python 从 cmd 运行它,即不是从 Cygwin 运行,则不会出现问题。
更新:
更仔细地查看源代码,看起来 CreateSemaphore C 函数接受了一个“名称”参数,如果具有此名称的信号量已经存在,则会标记错误 ERROR_ALREADY_EXISTS。但是,在 Modules/_multiprocessing/semaphore.c 中的 python 源代码中,此函数在没有名称参数的情况下调用,因此不应发生这种情况。我猜这只是 cygwin 信号量实现中的一个怪癖。
编辑2: 我现在有这样的设置:
import multiprocessing
for i in range(10):
count = 0
while True:
try:
q = multiprocessing.Queue()
break
except OSError as exc:
if exc.errno == 17:
count += 1
else:
raise # catch other errors, but this has never happened
print "iterations %d" % count
我注意到一个怪癖:Queue 构造函数失败的次数总是小于或等于 3003,而恰好 3000 也经常出现。此外,一旦构造函数成功了一次,它就不会在 for 循环的其余迭代中再次失败。
我还是一脸懵逼!我曾尝试在队列本身上使用 gc.collect、time.sleep、调用 close 或 del,但这些似乎都没有任何影响。如果这确实是操作系统清理信号量的问题,是否有办法通过系统调用“强制”这种情况发生?
【问题讨论】:
-
我无法在 Linux 上重现此问题,这似乎是特定于窗口的问题。我的猜测是 - 这是队列信号量的垃圾收集问题,也许是在 Windows 上识别信号量的方式?但这只是一个猜测,我在这里唯一的输入是它似乎是特定于 Windows 的。
-
@Not_a_Golfer 我安装了一个 windows python 版本并测试了它(应该首先做这件事)......看起来这是一个 Cygwin 特定的问题。
-
在 Windows 7 上的 Cygwin 中的 Python 2.6.5 上测试,无法重现。
-
uname -a 从 cygwin 内部给出 CYGWIN_NT-6.1-WOW64 ... 1.7.9(0.237/5/3)
-
我也在 Win 7、python 2.6.7、cygwin 1.7.11 上运行良好。
标签: python cygwin multiprocessing message-queue