2012-10-23 15 views
8

threading.Conditionが正しくサルにパッチされているかどうかを確認しながら、threading.Thread(…).start()gevent.spawn(…)とは異なる動作をしています。`gevent.spawn`がmonkeypatched` threading.Thread() `と異なるのはなぜですか?

は考えてみましょう:

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

注意を、具体的には、2件のコメントが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()(第2ブロック)は、すべてが期待どおりに動作:

gevent.spawnと)最初のラインを使用して、最初のthread.join()は、例外が発生します。

これはなぜでしょうか? gevent.spawn()Thread(…).start()の違いは何ですか?あなたのコード内で起こる何

答えて

5

は、あなたが使用してコードにそう明示的に行うまでgeventは、コンテキストスイッチをトリガーしませんので、あなたがあなたthreadsリストで作成したgreenletsはまだチャンスが実行する必要がなかったことです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()は と表示されます。小島のすべてをお知らせします。

HTH、

関連する問題