Python线程:将Event.set()真正通知每个等待的线程



如果我有一个threading.Event和以下两行代码:

event.set()
event.clear()

我有一些线程正在等待那个事件。

我的问题与调用set()方法时会发生什么有关:

  • 我能绝对确定所有等待的线程都会得到通知吗?(即Event.set()"通知"线程)
  • 或者,这两行的执行速度如此之快,以至于一些线程可能仍在等待?(即Event.wait()轮询事件的状态,该状态可能已被再次"清除")

谢谢你的回答!

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

很容易验证事情是否按预期运行(注意:这是Python 2代码,需要适应Python 3):

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

如果运行上面的脚本并终止,一切都应该很好:-)注意,有一百个线程正在等待事件的设置;它已经设置好并立即清除;所有线程都应该看到这一点,并且应该终止(尽管不是以任何确定的顺序,并且"全部完成"可以在"按enter"提示后的任何位置打印,而不仅仅是在最后。

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

最新更新