【问题标题】:Python threading: will Event.set() really notify every waiting threadPython 线程:Event.set() 会真正通知每个等待的线程吗
【发布时间】:2011-06-06 16:19:04
【问题描述】:

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

event.set()
event.clear()

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

我的问题与调用set() 方法时发生的情况有关:

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

感谢您的回答!

【问题讨论】:

    标签: python multithreading events wait


    【解决方案1】:

    在 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.7 中,如果您指定超时,来自 event.wait() 的返回值是不可靠的。见bugs.python.org/issue13502
    【解决方案2】:

    验证事情是否按预期工作很容易(注意:这是 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.'
    

    如果您运行上述脚本并且它终止了,那么一切都应该很好:-) 请注意,有一百个线程正在等待设置事件;它立即设置并清除;所有线程都应该看到这一点并应该终止(尽管不是以任何明确的顺序,并且可以在“Press enter”提示之后的任何地方打印“All done”,而不仅仅是在最后。

    【讨论】:

      【解决方案3】:

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

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2012-04-17
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多