python threading: будет Event.set () действительно уведомлять каждый ожидающий поток - PullRequest
17 голосов
/ 06 июня 2011

Если у меня есть threading.Event и две следующие строки кода ...

event.set()
event.clear()

... и у меня есть несколько потоков, ожидающих этого события.

Мой вопрос связан с тем, что происходит при вызове метода set ():

  • Могу ли я быть АБСОЛЮТНО уверенным, что все ожидающие потоки будут уведомлены?(т. е. Event.set () «уведомляет» потоки)
  • Или может случиться, что эти две строки выполняются так быстро друг за другом, что некоторые потоки все еще могут ожидать?(т.е. Event.wait () опрашивает состояние события, которое может быть уже «очищено» снова)

Спасибо за ваши ответы!

Ответы [ 2 ]

13 голосов
/ 06 июня 2011

Достаточно просто проверить, что все работает как положено:

import threading

e = threading.Event()
threads = []

def runner():
    tname = threading.current_thread().name
    print 'Thread waiting for event: %s' % tname
    e.wait()
    print 'Thread got event: %s' % tname

for t in range(100):
    t = threading.Thread(target=runner)
    threads.append(t)
    t.start()

raw_input('Press enter to set and clear the event:')
e.set()
e.clear()
for t in threads:
    t.join()
print 'All done.'

Если вы запустите приведенный выше скрипт и он завершится, все должно быть хорошо :-) Обратите внимание, что сотни потоков ждут событияустановить;это установлено и очищено сразу;все потоки должны видеть это и должны завершаться (хотя и не в каком-то определенном порядке, и «Все готово» может быть напечатано в любом месте после приглашения «Нажать ввод», а не только в самом конце.

11 голосов
/ 06 июня 2011

Во внутренних компонентах Python событие реализуется с помощью объекта Condition().

При вызове метода event.set() notify_all()условия вызывается (после получения блокировки, чтобы быть уверенным, что она не прервана), тогда все потоки получают уведомление (блокировка снимается только тогда, когда все потоки уведомлены), так что вы можете быть уверены, что все потоки будутэффективно получать уведомления.

Теперь очистка события сразу после уведомления не является проблемой .... пока вы не хотите проверять значение события в ожидающих потоках с помощью event.is_set(), но вы тольконужна такая проверка, если вы ожидаете с таймаутом.

Примеры:

псевдокод, который работает:

#in main thread
event = Event()
thread1(event)
thread2(event)
...
event.set()
event.clear()

#in thread code
...
event.wait()
#do the stuff

псевдокод, который может не работать:

#in main thread
event = Event()
thread1(event)
thread2(event)
...
event.set()
event.clear()

#in thread code
...
while not event.is_set():
   event.wait(timeout_value)
#do the stuff

Отредактировано: в python> = 2.7 вы все еще можете ждать событие с таймаутом и быть уверенным в состоянии события:

event_state = event.wait(timeout)
while not event_state:
    event_state = event.wait(timeout)
...