Python threading: can I sleep on two threading.Event()s simultaneously?

前端 未结 8 1626
悲&欢浪女
悲&欢浪女 2020-12-09 03:35

If I have two threading.Event() objects, and wish to sleep until either one of them is set, is there an efficient way to do that in python? Clearly I could do

8条回答
  •  离开以前
    2020-12-09 04:03

    Here is a non-polling non-excessive thread solution: modify the existing Events to fire a callback whenever they change, and handle setting a new event in that callback:

    import threading
    
    def or_set(self):
        self._set()
        self.changed()
    
    def or_clear(self):
        self._clear()
        self.changed()
    
    def orify(e, changed_callback):
        e._set = e.set
        e._clear = e.clear
        e.changed = changed_callback
        e.set = lambda: or_set(e)
        e.clear = lambda: or_clear(e)
    
    def OrEvent(*events):
        or_event = threading.Event()
        def changed():
            bools = [e.is_set() for e in events]
            if any(bools):
                or_event.set()
            else:
                or_event.clear()
        for e in events:
            orify(e, changed)
        changed()
        return or_event
    

    Sample usage:

    def wait_on(name, e):
        print "Waiting on %s..." % (name,)
        e.wait()
        print "%s fired!" % (name,)
    
    def test():
        import time
    
        e1 = threading.Event()
        e2 = threading.Event()
    
        or_e = OrEvent(e1, e2)
    
        threading.Thread(target=wait_on, args=('e1', e1)).start()
        time.sleep(0.05)
        threading.Thread(target=wait_on, args=('e2', e2)).start()
        time.sleep(0.05)
        threading.Thread(target=wait_on, args=('or_e', or_e)).start()
        time.sleep(0.05)
    
        print "Firing e1 in 2 seconds..."
        time.sleep(2)
        e1.set()
        time.sleep(0.05)
    
        print "Firing e2 in 2 seconds..."
        time.sleep(2)
        e2.set()
        time.sleep(0.05)
    

    The result of which was:

    Waiting on e1...
    Waiting on e2...
    Waiting on or_e...
    Firing e1 in 2 seconds...
    e1 fired!or_e fired!
    
    Firing e2 in 2 seconds...
    e2 fired!
    

    This should be thread-safe. Any comments are welcome.

    EDIT: Oh and here is your wait_for_either function, though the way I wrote the code, it's best to make and pass around an or_event. Note that the or_event shouldn't be set or cleared manually.

    def wait_for_either(e1, e2):
        OrEvent(e1, e2).wait()
    

提交回复
热议问题