Gevent猴子补丁破坏多进程
我正在尝试使用多进程的池来运行一组进程,每个进程都会运行一个gevent的绿色线程池。这样做的原因是因为网络活动和CPU活动都很频繁,所以为了最大化我的带宽和所有的CPU核心,我需要同时使用多个进程和gevent的异步猴子补丁。我使用多进程的管理器创建了一个队列,进程们可以通过这个队列获取需要处理的数据。
下面是代码的一个简化片段:
import multiprocessing
from gevent import monkey
monkey.patch_all(thread=False)
manager = multiprocessing.Manager()
q = manager.Queue()
这是它产生的异常:
Traceback (most recent call last):
File "multimonkeytest.py", line 7, in <module>
q = manager.Queue()
File "/usr/local/Cellar/python/2.7.2/Frameworks/Python.framework/Versions/2.7/lib/python2.7/multiprocessing/managers.py", line 667, in temp
token, exp = self._create(typeid, *args, **kwds)
File "/usr/local/Cellar/python/2.7.2/Frameworks/Python.framework/Versions/2.7/lib/python2.7/multiprocessing/managers.py", line 565, in _create
conn = self._Client(self._address, authkey=self._authkey)
File "/usr/local/Cellar/python/2.7.2/Frameworks/Python.framework/Versions/2.7/lib/python2.7/multiprocessing/connection.py", line 175, in Client
answer_challenge(c, authkey)
File "/usr/local/Cellar/python/2.7.2/Frameworks/Python.framework/Versions/2.7/lib/python2.7/multiprocessing/connection.py", line 409, in answer_challenge
message = connection.recv_bytes(256) # reject large message
IOError: [Errno 35] Resource temporarily unavailable
我认为这可能是因为普通的socket模块和gevent的socket模块在行为上有一些不同。
如果我在子进程中进行猴子补丁,队列可以成功创建,但当子进程尝试从队列中获取数据时,会出现一个非常相似的异常。由于子进程需要进行大量的网络请求,所以socket确实需要进行猴子补丁。
这是我使用的gevent版本,我认为这是最新的:
>>> gevent.version_info
(1, 0, 0, 'alpha', 3)
有什么想法吗?
5 个回答
如果你使用原始的队列,那么即使你对 socket 进行了修改,你的代码也会正常运行。
import multiprocessing
from gevent import monkey
monkey.patch_all(thread=False)
q= multiprocessing.Queue()
在使用gevent的时候,应用多进程会遇到一些问题。不过,你的想法是合理的(“有很多网络活动,同时也有很多CPU活动”)。如果你有兴趣,可以看看http://gehrcke.de/gipc。这个工具主要是为了你的使用场景设计的。通过gipc,你可以很方便地创建几个完全支持gevent的子进程,让它们通过管道互相交流,或者和父进程交流。
如果你有具体的问题,随时可以问我。
使用 monkey.patch_all(thread=False, socket=False)
我在类似的情况下遇到了同样的问题,追踪到 gevent/monkey.py
文件的第115行,在 patch_socket()
函数里:_socket.socket = socket.socket
。把这一行注释掉就能解决问题。
这里是 gevent 把标准库里的 socket
库替换成它自己的版本的地方。multiprocessing.connection
这个模块使用 socket
库非常频繁,显然对这个变化不太能接受。
具体来说,你会在任何你导入的模块中看到这个问题,只要它调用了 gevent.monkey.patch_all()
而没有把 socket=False
设置上。在我的情况下,是 grequests
这样做的,所以我不得不覆盖 socket 模块的补丁来修复这个错误。