Python中如何在使用gevent patch thread的同时兼容multiprocessing.pool?

由于用到了 pymongo, 需要 patch thread, 但 patch thread 又会破坏 multiprocessing.Queue.

如果没有办法兼容,那大概就要用外部的 celery 代替 multiprocessing.pool 了吧?


Python中如何在使用gevent patch thread的同时兼容multiprocessing.pool?
5 回复

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

注意几个要点:

  1. 顺序很重要:一定要在import multiprocessing相关模块之前执行patch
  2. 使用if name == ‘main:这是multiprocessing在Windows和macOS上的硬性要求
  3. 避免在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

回到顶部