Почему `gevent.икра "отличается от обезьяны".Thread()`?
при двойной проверке этого threading.Condition
правильно патченные, я заметил, что monkeypatched 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,
Thread(…).start()
(второй блок), все работает, как ожидалось.
почему будет ли это? В чем разница между gevent.spawn()
и Thread(…).start()
?
1 ответов
что происходит в вашем коде, так это то, что это что вы создали в вас threads
список еще не имел возможности быть выполненным, потому что gevent
не вызовет переключатель контекста, пока вы не сделаете это явно в своем коде, используя gevent.sleep()
и такой или неявно, вызывая функцию, которая блокирует, например,semaphore.wait()
или путем уступать и так далее ..., чтобы увидеть, что вы можете вставить печать до cv.wait()
и смотрите, что он называется только после cv.notify_all()
is крикнул:
def wait_on_cv(x):
cv.acquire()
print 'acquired ', x
cv.wait()
....
таким образом, простым исправлением вашего кода будет вставка чего-то, что вызовет переключатель контекста после создания списка это, например:
...
threads = [ gevent.spawn(wait_on_cv, x) for x in range(10) ]
gevent.sleep() # Trigger a context switch
...
Примечание: Я все еще новичок в gevent
поэтому я не знаю, правильно ли это сделать :)
сюда все это будет иметь возможность быть выполненным, и каждый из них вызовет переключатель контекста при вызове cv.wait()
и в то же время
зарегистрируйте их самостоятельно к официантам условия так, что когда cv.notify_all()
называется это
уведомит всех это.
HTH,