2011-06-06 77 views
14

如果我有一个threading.Event和下面的代码两行...蟒蛇线程:将Event.set()确实通知每一个等待的线程

event.set() 
event.clear() 

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

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

  • 我可以绝对肯定,所有等待的线程(S)将被通报? (即Event.set()“通知”线程)
  • 或者可能发生这样的情况:这两行执行得如此之快以致于某些线程可能仍在等待呢? (即Event.wait()轮询事件的状态,可能已经“清除”了)

感谢您的回答!

回答

9

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

请注意,在Python 2.7中,如果你指定了超时时间,那么从event.wait()返回的值是不可靠的。请参阅https://bugs.python.org/issue13502 – 2017-12-18 17:11:18

11

这是很容易验证的东西按预期工作:

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

如果你运行上面的脚本,它终止时,都应该是很好:-)注意百线程都在等待该事件是组;它立即被设置和清除;所有的线程应该看到这个并且应该终止(虽然不是以任何确定的顺序,并且“所有完成”可以在“按下输入”提示符后的任何地方打印,而不仅仅是在最后。