4

我正在用 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 的代码是在一个本身就是一个长时间运行的过程的框架内完成的。

4

3 回答 3

5

如果您希望您的主线程比您的任何工作线程持续更长的时间,那么没有什么需要您调用joingevent。

调用的唯一原因join是确保主线程的持续时间至少与所有工作线程一样长(这样程序就不会提前终止)。

于 2012-07-07T17:46:12.407 回答
0

为什么不使用连接的管道或类似的管道生成一个子进程,然后,而不是可调用的,只需将数据放在管道上,让子进程在带外完全处理它。

于 2012-07-08T15:08:51.120 回答
0

了解 Python 中的异步/多处理中所述,asyncoro框架支持异步并发进程。您可以运行数万或数十万个并发进程;作为参考,运行 100,000 个简单进程大约需要 200MB。如果您愿意,您可以将系统其余部分的线程和协程与 asyncoro 混合使用(前提是线程和协程不共享变量,但使用协程接口函数发送消息等)。

于 2012-07-13T01:28:39.237 回答