为什么 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].value
从 fooFn
中得到了正确的值。这意味着 threads[0]
greenlet 被执行了。
当我只将 threads[1]
greenlet 传递给 gevent.joinall
时,为什么会发生这种情况?
我如何确保只执行那些实际传递给 gevent.joinall
的 greenlets?
当您调用 greenlet.spawn()
时,您的 greenlets 会立即 安排。换句话说,它们是在您调用 spawn()
时立即创建和启动的。这就是第一个 greenlet 完成的原因 运行 - 从您生成它们的那一刻起,两个 greenlet 都在执行,并且当您开始查找 greenlet 1 的结果时,它们都已完成执行。
gevent.joinall()
不执行 greenlets - 它只告诉主线程(实际上 spawn
ed 它们的线程)等待作为参数传入的那些完成 运行.不调用 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
以只执行那个。
我有以下 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].value
从 fooFn
中得到了正确的值。这意味着 threads[0]
greenlet 被执行了。
当我只将 threads[1]
greenlet 传递给 gevent.joinall
时,为什么会发生这种情况?
我如何确保只执行那些实际传递给 gevent.joinall
的 greenlets?
当您调用 greenlet.spawn()
时,您的 greenlets 会立即 安排。换句话说,它们是在您调用 spawn()
时立即创建和启动的。这就是第一个 greenlet 完成的原因 运行 - 从您生成它们的那一刻起,两个 greenlet 都在执行,并且当您开始查找 greenlet 1 的结果时,它们都已完成执行。
gevent.joinall()
不执行 greenlets - 它只告诉主线程(实际上 spawn
ed 它们的线程)等待作为参数传入的那些完成 运行.不调用 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
以只执行那个。