2012-10-23 14 views
8

जबकि threading.Condition डबल चेकिंग सही ढंग से बंदर है, मैंने देखा कि एक बंदरगाह threading.Thread(…).start()gevent.spawn(…) से अलग व्यवहार करता है।`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 के साथ शुरू दो टिप्पणी नहीं।

 
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 

हालांकि, Thread(…).start() (दूसरे खंड), सब कुछ उम्मीद के रूप में काम करता है:

पहली पंक्ति (gevent.spawn के साथ) का उपयोग कर, पहले thread.join() एक अपवाद को जन्म देती है।

यह क्यों होगा? gevent.spawn() और Thread(…).start() के बीच क्या अंतर है?

उत्तर

5

क्या अपने कोड में होती हैं greenlets है कि आप आप threads सूची में बनाया है अभी तक मौका निष्पादित करने के लिए नहीं था जब तक आप का उपयोग कर अपने कोड में इतना स्पष्ट रूप से करते हैं, क्योंकि gevent एक संदर्भ स्विच ट्रिगर नहीं करेगा है gevent.sleep() और इस तरह के या निहित रूप से एक समारोह को बुलाकर उदा semaphore.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 लिए नया हूँ तो मैं अगर यह करने के लिए सही तरीका है पता नहीं है यह :)

इस तरह सभी greenlets मौका निष्पादित किया जाना है और उनमें से हर एक, जब वे cv.wait() फोन और मतलब समय में वे उन्हें हालत वेटर करने के लिए स्वयं को पंजीकृत करेगा एक संदर्भ स्विच ट्रिगर किया जाएगा होगा ताकि जब cv.notify_all() इसे कहा जाता है सभी ग्रीनलेट को सूचित करेगा।

एचटीएच,

संबंधित मुद्दे