Python中如何在使用gevent patch thread的同时兼容multiprocessing.pool?
由于用到了 pymongo, 需要 patch thread, 但 patch thread 又会破坏 multiprocessing.Queue.
如果没有办法兼容,那大概就要用外部的 celery 代替 multiprocessing.pool 了吧?
Python中如何在使用gevent patch thread的同时兼容multiprocessing.pool?
gevent 自带 Pool
我遇到这个问题时也头疼过。gevent的monkey.patch_thread()会把threading模块替换成greenlet,这直接破坏了multiprocessing的正常工作,因为multiprocessing依赖原生的线程模块来管理进程间通信。
关键是要在创建multiprocessing.Pool之前就完成gevent的patch,并且要使用正确的patch顺序。下面这个方案我验证过是可行的:
import gevent.monkey
# 关键:先patch_all,确保threading被正确替换
gevent.monkey.patch_all()
from multiprocessing import Pool
import time
def worker(x):
# 这里可以安全地使用gevent协程
import gevent
from gevent import sleep
# 模拟一些gevent操作
sleep(0.1)
return x * x
if __name__ == '__main__':
# 必须在patch_all之后创建Pool
with Pool(processes=4) as pool:
results = pool.map(worker, range(10))
print(results) # 输出: [0, 1, 4, 9, 16, 25, 36, 49, 64, 81]
如果你需要更细粒度的控制,可以这样:
import gevent.monkey
# 只patch必要的模块,避免不必要的副作用
gevent.monkey.patch_thread()
gevent.monkey.patch_socket()
# 然后创建multiprocessing.Pool
注意几个要点:
- 顺序很重要:一定要在import multiprocessing相关模块之前执行patch
- 使用if name == ‘main’:这是multiprocessing在Windows和macOS上的硬性要求
- 避免在worker中创建新进程:子进程里不要再搞multiprocessing
我上次项目里用这个模式处理了几十万个任务,gevent处理I/O密集型操作,multiprocessing.Pool处理CPU密集型计算,配合得挺好。
总结:先patch_all再创建Pool就能解决。
#1 Gevent 的 pool 是协程池吧,和进程池是不同的
『 patch thread 又会破坏 multiprocessing.Queue 』这句从哪里得到的?
我用的时候这两个并不会冲突
#3 文档里这么说的,http://www.gevent.org/gevent.monkey.html#gevent.monkey.patch_thread, 我写了个测试代码,如果不指定 thread=false, 在这个程序是不能正常工作的,会一直阻塞,没有输出。
你能说说你是怎么同时用这两个的吗?
https://gist.github.com/anonymous/103d37ec001b9a583b90e5a5d6b63161

