Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/multithreading/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python 为什么“gevent.spawn”不同于“threading.Thread()”?_Python_Multithreading_Gevent - Fatal编程技术网

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()
时调用它 将通知所有的小绿球

嗯,