我在REST服务中工作,该服务基本上是库的包装器。我使用烧瓶和gunicorn。基本上,服务中的每个端点都映射到库中的不同功能。
发生一些对库的调用可能需要很长时间才能返回,这使得一旦服务开始收到一些请求,我的服务就会耗尽工作人员。现在我使用默认的gunicorn工作者(同步)。
我想使用gevent worker以便能够接收更多请求,因为并非每个端点都需要花费很长时间才能执行。但是,库中的函数不使用任何可修补的gevent函数,这意味着它不会合作安排到另一个绿色线程。
我有这样的想法,即使用一个线程或进程池来异步处理对库的调用,然后gunicorn生成的每个绿色线程都会睡眠,直到进程没有完成。这个想法有意义吗?
是否可以使用multiprocessing.Process与gevent?然后让join方法放弃对另一个绿色线程的控制,只在进程结束时返回?
答案 0 :(得分:1)
是的,在gevent
内使用(实际)线程或进程来完成合理的代码需要异步但不能由gevent
进行修改。
当然,获得右键优先权可能很棘手,因为你可能有monkeypatched threading
,其次,因为你希望你的协作线程能够阻塞池或池结果而不会阻塞整个主线。
但这正是gevent.threadpool
的用途。
如果您在非concurrent.futures.ThreadPoolExecutor
应用中使用了gevent
,则monkeypatch threading
然后使用gevent.threadpool.ThreadPoolExecutor
。
如果您在非multiprocessing.dummy.Pool
应用中使用了gevent
,则monkeypatch threading
然后使用gevent.threadpool.ThreadPool
。
无论哪种方式,map
,submit
,apply_async
等方法的工作方式与您预期的方式非常相似。 Future
和AsyncResult
对象可以很好地与greenlets一起使用;你可以gevent.wait
个东西,或附加回调(它将作为greenlets运行)等等。大多数时候它只是像魔术一样工作,其余的时间它不太难以弄明白。
使用进程代替线程是可行的,但不是很好。 AFAIK,对于multiprocessing.Process
或multiprocessing.Pool
完整的任何内容都没有包装,尝试使用普通multiprocessing
只是挂起。您可以手动fork
,如果您不在Windows上,但这是关于所有内置的。如果您真的需要多处理,您可能需要做一些多层次的事情,你的greenlets不与一个进程交谈,而是与一个创建管道,分支,高手,然后代理gevent世界和子进程之间的代理交谈。
如果电话花了很长时间,因为他们正在等待来自后端服务的I / O,或等待子进程,或者正在进行GIL释放numpy工作,我就不会费心去做做multiprocessing
。但是如果他们花了很长时间因为他们正在燃烧CPU ......那么你需要让多处理工作,或者更低级别,然后剥离subprocess.Popen([sys.executable, 'workerscript.py'])
。