为什么 python gevent.joinall 执行所有 greenlets

Why python gevent.joinall execute all 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 的 greenlets?

当您调用 greenlet.spawn() 时,您的 greenlets 会立即 安排。换句话说,它们是在您调用 spawn() 时立即创建和启动的。这就是第一个 greenlet 完成的原因 运行 - 从您生成它们的那一刻起,两个 greenlet 都在执行,并且当您开始查找 greenlet 1 的结果时,它们都已完成执行。

gevent.joinall() 不执行 greenlets - 它只告诉主线程(实际上 spawned 它们的线程)等待作为参数传入的那些完成 运行.不调用 joinall 存在主线程在 joinall() 中的 greenlets 结果到达之前完成并退出的风险,然后谁来处理他们的结果?

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

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

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

    在控制台中调用 joinall() 没有任何意义(尽管如果你想保证下次调用 greenlet 上的函数时会从 greenlet 获得结果,这是个好主意)

  • 如果您想保证只执行 greenlet 1 而不执行 greenlet 2,则不应该调用 spawn()。相反,read what the docs say:

    To start a new greenlet, pass the target function and its arguments to Greenlet constructor and call start():

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

    >>> g.start()

    or use classmethod spawn() which is a shortcut that does the same:

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

使用start 指示greenlet 应在此时启动运行 是个好主意。所以:创建两个 greenlet 对象,并且只在其中一个上调用 start 以只执行那个。