2012-10-23 19 views
8

threading.Condition'un doğru bir şekilde denetlendiğini kontrol ederken, bir maymun resmi threading.Thread(…).start()'un gevent.spawn(…)'dan farklı davrantığını fark ettim.Neden "gevent.spawn" bir monkeypatched `threading.Thread()` dan farklı?

düşünün:

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() 

Not özellikle iki yorum XXX ile başlayan.

 
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 

Ancak Thread(…).start() (ikinci blok), her şey beklendiği gibi çalışır:

(gevent.spawn ile) birinci satırını kullanarak, ilk thread.join() bir özel durum oluşturur.

Neden böyle olur? gevent.spawn() ve Thread(…).start() arasındaki fark nedir? Kodunuzdaki gerçekleşmesi ne

cevap

5

kullanmakta kodunuzda bu kadar açık bir şekilde yapana kadar gevent içeriği geçiş tetiklemez çünkü sen threads listede yarattık greenlets henüz şans yürütülecek yoktu olmasıdır gevent.sleep() ve bu gibi veya dolaylı olarak engelleyen bir işlevi çağırarak semaphore.wait() veya cv.wait() önce bir baskı yerleştirin ve cv.notify_all() denir sonra deniyor görebilirsiniz görmek için, ... vb verimli ve ölçütü:

def wait_on_cv(x): 
    cv.acquire() 
    print 'acquired ', x 
    cv.wait() 
    .... 

Yani koduna kolay bir düzeltme eklemek için olacak Eğer greenlets listenizi oluşturduktan sonra içeriği geçiş tetikleyecek bir şey, örnek:

... 
threads = [ gevent.spawn(wait_on_cv, x) for x in range(10) ] 
gevent.sleep() # Trigger a context switch 
... 

Not: Ben gevent yeni hala duyuyorum bunu yapmanın doğru yolu eğer öyleyse ben bilmiyorum o :)

tüm greenlets onlar cv.wait() arayıp bu arada onlar durum Garsonlar onlara kendini kaydedecektir zaman bir bağlam anahtarı tetikleyecek yürütülecek şans ve bunların her birini olacaktır Bu şekilde zaman ki cv.notify_all() denir tüm greenlets bildirir.

HTH,

İlgili konular