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

前端 未结 8 1628
悲&欢浪女
悲&欢浪女 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
    def wait_for_event_timeout(*events):
        while not all([e.isSet() for e in events]):
            #Check to see if the event is set. Timeout 1 sec.
            ev_wait_bool=[e.wait(1) for e in events]
            # Process if all events are set. Change all to any to process if any event set
            if all(ev_wait_bool):
                logging.debug('processing event')
            else:
                logging.debug('doing other work')
    
    
    e1 = threading.Event()
    e2 = threading.Event()
    
    t3 = threading.Thread(name='non-block-multi',
                          target=wait_for_event_timeout,
                          args=(e1,e2))
    t3.start()
    
    logging.debug('Waiting before calling Event.set()')
    time.sleep(5)
    e1.set()
    time.sleep(10)
    e2.set()
    logging.debug('Event is set')
    
    0 讨论(0)
  • 2020-12-09 04:08

    One solution (with polling) would be to do sequential waits on each Event in a loop

    def wait_for_either(a, b):
        while True:
            if a.wait(tunable_timeout):
                break
            if b.wait(tunable_timeout):
                break
    

    I think that if you tune the timeout well enough the results would be OK.


    The best non-polling I can think of is to wait for each one in a different thread and set a shared Event whom you will wait after in the main thread.

    def repeat_trigger(waiter, trigger):
        waiter.wait()
        trigger.set()
    
    def wait_for_either(a, b):
        trigger = threading.Event()
        ta = threading.Thread(target=repeat_trigger, args=(a, trigger))
        tb = threading.Thread(target=repeat_trigger, args=(b, trigger))
        ta.start()
        tb.start()
        # Now do the union waiting
        trigger.wait()
    

    Pretty interesting, so I wrote an OOP version of the previous solution:

    class EventUnion(object):
        """Register Event objects and wait for release when any of them is set"""
        def __init__(self, ev_list=None):
            self._trigger = Event()
            if ev_list:
                # Make a list of threads, one for each Event
                self._t_list = [
                    Thread(target=self._triggerer, args=(ev, ))
                    for ev in ev_list
                ]
            else:
                self._t_list = []
    
        def register(self, ev):
            """Register a new Event"""
            self._t_list.append(Thread(target=self._triggerer, args=(ev, )))
    
        def wait(self, timeout=None):
            """Start waiting until any one of the registred Event is set"""
            # Start all the threads
            map(lambda t: t.start(), self._t_list)
            # Now do the union waiting
            return self._trigger.wait(timeout)
    
        def _triggerer(self, ev):
            ev.wait()
            self._trigger.set()
    
    0 讨论(0)
提交回复
热议问题