web-dev-qa-db-ja.com

pythonスレッド化:Event.set()は実際にすべての待機中のスレッドに通知します

Threading.Eventと次の2行のコードがある場合...

event.set()
event.clear()

...そして私にはそのイベントを待っているスレッドがいくつかあります。

私の質問は、set()メソッドを呼び出すとどうなるかに関するものです。

  • 待機中のすべてのスレッドに通知されることを絶対に確信できますか? (つまり、Event.set()はスレッドに「通知」します)
  • または、これらの2つの行が次々と実行されて、一部のスレッドがまだ待機している可能性がありますか? (つまり、Event.wait()はイベントの状態をポーリングしますが、これはすでに「クリア」されている可能性があります)

あなたの答えをありがとう!

18
Criss

物事が期待どおりに機能することを確認するのは簡単です。

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.'

上記のスクリプトを実行して終了した場合、すべてが順調に進んでいるはずです:-)イベントが設定されるのを100のスレッドが待機していることに注意してください。すぐに設定およびクリアされます。すべてのスレッドがこれを認識して終了する必要があります(ただし、明確な順序ではなく、「すべて完了」は、最後だけでなく、「Enterキーを押す」プロンプトの後のどこにでも印刷できます。

13
Vinay Sajip

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

編集済み:in python> = 2.7でも、タイムアウトのあるイベントを待機し、イベントの状態を確認できます:

event_state = event.wait(timeout)
while not event_state:
    event_state = event.wait(timeout)
11
Cédric Julien

Python 3 +

それが機能することを確認する方が簡単です

import threading
import time

lock = threading.Lock() # just to sync printing
e = threading.Event()
threads = []

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

for t in range(8): # Create 8 threads could be 100's
    t = threading.Thread(target=runner)
    threads.append(t)
    t.start()

time.sleep(1) # force wait until set/clear
e.set()
e.clear()
for t in threads:
    t.join()    

print('Done')
0
eusoubrasileiro