我正在用 Python 实现一个非常小的库,它必须是非阻塞的。
在某些生产代码上,在某些时候,将完成对该库的调用,并且它需要完成自己的工作,以最简单的形式,它是一个需要将一些信息传递给服务的可调用对象。
这种“将信息传递给服务”是一项非密集型任务,可能会将一些数据发送到 HTTP 服务或类似的东西。它也不需要并发或共享信息,但是它确实需要在某个时候终止,可能会超时。
我以前使用过这个threading
模块,它似乎是最合适的东西,但是使用这个库的应用程序太大了,我担心会达到线程限制。
在本地测试中,我能够在产生大约 2500 个线程时达到该限制。
很有可能(考虑到应用程序的大小)我可以轻松达到该限制。这也让我厌倦了使用队列,因为在其中高速放置任务会影响内存。
我也看过,gevent
但我看不到一个能够产生一些可以做一些工作并在不加入的情况下终止的例子。我所经历的例子是调用.join()
一个生成的Greenlet
或一组greenlets。
我不需要知道正在完成的工作的结果!它只需要启动并尝试与 HTTP 服务对话,如果没有,它会在合理的超时下死掉。
我是否误解了指南/教程gevent
?是否有任何其他可能性以完全非阻塞的方式产生一个不能达到 ~2500 限制的可调用对象?
这是 Threading 中的一个简单示例,它可以按我的预期工作:
from threading import Thread
class Synchronizer(Thread):
def __init__(self, number):
self.number = number
Thread.__init__(self)
def run(self):
# Simulating some work
import time
time.sleep(5)
print self.number
for i in range(4000): # totally doesn't get past 2,500
sync = Synchronizer(i)
sync.setDaemon(True)
sync.start()
print "spawned a thread, number %s" % i
这就是我用 gevent 尝试过的,它显然会在最后阻塞以查看工人做了什么:
def task(pid):
"""
Some non-deterministic task
"""
gevent.sleep(1)
print('Task', pid, 'done')
for i in range(100):
gevent.spawn(task, i)
编辑:
我的问题源于我对gevent
. 虽然Thread
代码确实产生了线程,但它也阻止了脚本在执行某些工作时终止。
gevent
在上面的代码中并没有真正做到这一点,除非你添加一个.join()
. 为了让gevent
代码对生成的 greenlets 做一些工作,我所要做的就是让它成为一个长时间运行的过程。这绝对解决了我的问题,因为需要生成 greenlets 的代码是在一个本身就是一个长时间运行的过程的框架内完成的。