我有以下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]
绿绿灯。
当我只将threads[1]
绿绿灯传递给gevent.joinall
时,为什么会发生这种情况?
如何确保只执行那些实际传递给gevent.joinall
的greenlet?
当您调用greenlet.spawn()
时,您的绿绿灯会立即安排。换句话说,它们是在您调用spawn()
时立即创建和启动的。这就是为什么第一个greenlet已经运行完毕——两个greenlet从你生成它们的那一刻起就在执行,当你从greenlet 1中查找结果时,它们都已经执行完毕。
gevent.joinall()
不执行greenlets——它只是告诉主线程(实际上是spawn
执行它们的线程)等待作为参数传入的线程完成运行。不调用joinall
会导致主线程在joinall()
中的greenlets的结果到达之前完成并退出,然后谁来处理他们的结果?
在这里,您做了两件应该更改的事情,以便看到gevents
的行为符合您的要求:
-
您在控制台REPL中调用了
joinall()
,而不是从脚本中调用。这里,主线程REPL保证不会在greenlets返回,因为REPL仅在调用
exit()
时结束或者指示EOF。然而,在一个没有即时用户交互的脚本中,你就没有这种奢侈了——当脚本中没有什么可做的时候,执行就结束了。这就是为什么我们调用join()
来确保主线程永远不会退出,并且让你的greenlet挂起,没有父线程可以返回。在控制台中调用
joinall()
是没有意义的(尽管如果你想保证下次在greenlet上调用函数时会从greenlet得到结果,这是个好主意) -
如果您想保证只执行greenlet 1,而不执行greenlet 2,则不应该调用
spawn()
。相反,请阅读文档中的内容:要启动新的greenlet,请将目标函数及其参数传递给Greenlet构造函数和调用start():
>>> g = Greenlet(myfunction, 'arg1', 'arg2', kwarg1=1)
>>> g.start()
或者使用类方法
spawn()
,这是一个做同样事情的快捷方式:>>> g = Greenlet.spawn(myfunction, 'arg1', 'arg2', kwarg1=1)
使用start
来指示greenlet此时应该开始运行是个好主意。所以:创建两个greenlet对象,只对其中一个对象调用start
,以便只执行该对象。