为什么python gevent.joinall会执行所有greenlet

时间:2016-04-01 14:27:44

标签: python gevent greenlets

我有以下Python代码:

>>> import gevent
>>> from gevent import monkey; monkey.patch_all()
>>>
>>> def fooFn(k):
...     return 'gevent_'+k
...
>>> threads = []
>>> threads.append(gevent.spawn(fooFn,'0'))
>>> threads.append(gevent.spawn(fooFn,'1'))
>>>
>>> gevent.joinall([threads[1]])
>>>
>>> print threads[1].value
gevent_1
>>> print threads[0].value
gevent_0
>>>

如上所示,threads[0].valuefooFn获得了适当的值。这意味着threads[0] greenlet已被执行。

为什么当我仅将threads[1] greenlet传递给gevent.joinall时,会发生这种情况?

如何确保只执行实际传递给gevent.joinall的那些greenlet?

1 个答案:

答案 0 :(得分:4)

当您致电greenlet.spawn()时,您的greenlet会立即立即安排。换句话说,当您致电spawn()时,它们会立即创建并启动。这就是为什么第一个greenlet完成运行的原因 - 两个greenlet都是从你生成它们的那一刻开始执行的,当你到处查找greenlet 1的结果时,两个都已完成执行。

gevent.joinall()没有执行greenlets - 它只告诉主线程(实际上spawn编辑它们的那个)等待传入的线程作为参数完成运行。在调用joinall中的greenlet结果之前,不调用joinall()会导致主线程完成和退出的风险,然后谁将处理他们的结果?

在这里,你做了两件事情,你应该改变,以便看到gevents表现得像你想要的那样:

  • 您在控制台REPL中调用了joinall(),而不是从脚本调用。

    这里,主线程 - REPL - 保证在之前没有完成 greenlets返回,因为REPL仅在您调用exit()时结束 或表示EOF。然而,在没有直接用户交互的脚本中,您没有那种奢侈 - 当脚本中没有任何内容可以执行时,执行就结束了。这就是为什么我们调用join()来确保主线程永远不会退出并让你的greenlet挂起而没有父级返回。

    在控制台中调用joinall()没有任何意义(尽管如果您想要保证,当您下次调用greenlet上的某个函数时,您将获得greenlet的结果,那么&#39 ;一个好主意)

  • 如果您想保证只执行greenlet 1而greenlet 2不是,则不应该调用spawn()。{li>

    相反,read what the docs say

      

    要启动新的greenlet,请将目标函数及其参数传递给   Greenlet构造函数和调用start():

         

    >>> g = Greenlet(myfunction, 'arg1', 'arg2', kwarg1=1)

         

    >>> g.start()

         

    或使用classmethod spawn()这是一个相同的快捷方式:

         

    >>> g = Greenlet.spawn(myfunction, 'arg1', 'arg2', kwarg1=1)

使用start表示此时应该开始运行的greenlet是个好主意。所以:创建两个greenlet对象,只在其中一个上调用start,只执行那个。