Python threading: can I sleep on two threading.Event()s simultaneously?
Question: 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 something with polling/timeouts, but I would like to really have the
thread sleep until one is set, akin to how `select` is used for file
descriptors.

So in the following implementation, what would an efficient non-polling
implementation of `wait_for_either` look like?

    
    
    a = threading.Event()
    b = threading.Event()
    
    wait_for_either(a, b)
    


Answer: Here is a non-polling non-excessive thread solution: modify the existing
`Event`s 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()
    

