Python 为什么“gevent.spawn”不同于“threading.Thread()”?
在仔细检查Python 为什么“gevent.spawn”不同于“threading.Thread()”?,python,multithreading,gevent,Python,Multithreading,Gevent,在仔细检查threading.Condition是否正确地进行了monkey修补时,我注意到monkey修补的threading.Thread(…).start()的行为与gevent.spawn(…)不同 考虑: from gevent import monkey; monkey.patch_all() from threading import Thread, Condition import gevent cv = Condition() def wait_on_cv(x):
threading.Condition
是否正确地进行了monkey修补时,我注意到monkey修补的threading.Thread(…).start()
的行为与gevent.spawn(…)
不同
考虑:
from gevent import monkey; monkey.patch_all()
from threading import Thread, Condition
import gevent
cv = Condition()
def wait_on_cv(x):
cv.acquire()
cv.wait()
print "Here:", x
cv.release()
# XXX: This code yields "This operation would block forever" when joining the first thread
threads = [ gevent.spawn(wait_on_cv, x) for x in range(10) ]
"""
# XXX: This code, which seems semantically similar, works correctly
threads = [ Thread(target=wait_on_cv, args=(x, )) for x in range(10) ]
for t in threads:
t.start()
"""
cv.acquire()
cv.notify_all()
print "Notified!"
cv.release()
for x, thread in enumerate(threads):
print "Joining", x
thread.join()
请特别注意以XXX
开头的两条注释
当使用第一行时(与gevent.spawn
),第一行thread.join()
引发异常:
Notified!
Joining 0
Traceback (most recent call last):
File "foo.py", line 30, in
thread.join()
File "…/gevent/greenlet.py", line 291, in join
result = self.parent.switch()
File "…/gevent/hub.py", line 381, in switch
return greenlet.switch(self)
gevent.hub.LoopExit: This operation would block forever
通知!
加入0
回溯(最近一次呼叫最后一次):
文件“foo.py”,第30行,在
thread.join()
文件“../gevent/greenlet.py”,第291行,在join中
结果=self.parent.switch()
开关中第381行的文件“../gevent/hub.py”
返回绿色小开关(自)
gevent.hub.LoopExit:此操作将永远阻塞
但是,线程(…).start()
(第二个块),一切正常
为什么会这样?
gevent.spawn()
和线程(…).start()之间有什么区别
?在您的代码中发生的是,您在线程列表中创建的greenlet还没有执行的机会,因为gevent
将不会触发上下文切换,除非您在代码中使用gevent.sleep()显式执行此操作
等等,或者通过调用阻止的函数来隐式调用,例如信号量.wait()
或者通过让步等等…,以查看您可以在cv.wait()
之前插入打印,并查看它仅在调用cv.notify_all()
之后才被调用:
def wait_on_cv(x):
cv.acquire()
print 'acquired ', x
cv.wait()
....
因此,代码的一个简单修复方法是在创建greenlets列表后插入触发上下文切换的内容,例如:
...
threads = [ gevent.spawn(wait_on_cv, x) for x in range(10) ]
gevent.sleep() # Trigger a context switch
...
注意:我对gevent还是新手,所以我不知道这样做是否正确:)
这样,所有的greenlet都有机会被执行,当它们调用cv.wait()
时,它们中的每一个都会触发上下文切换
将它们自己注册到条件等待者,以便在调用cv.notify_all()
时调用它
将通知所有的小绿球
嗯,