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

前端 未结 8 1635
悲&欢浪女
悲&欢浪女 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 03:50

    This is an old question, but I hope this helps someone coming from Google.
    The accepted answer is fairly old and will cause an infinite loop for twice-"orified" events.

    Here is an implementation using concurrent.futures

    import concurrent.futures
    from concurrent.futures import ThreadPoolExecutor
    
    def wait_for_either(events, timeout=None, t_pool=None):
        '''blocks untils one of the events gets set
    
        PARAMETERS
        events (list): list of threading.Event objects
        timeout (float): timeout for events (used for polling)
        t_pool (concurrent.futures.ThreadPoolExecutor): optional
        '''
    
        if any(event.is_set() for event in events):
            # sanity check
            pass
        else:
            t_pool = t_pool or ThreadPoolExecutor(max_workers=len(events))
            tasks = []
            for event in events:
                tasks.append(t_pool.submit(event.wait))
    
            concurrent.futures.wait(tasks, timeout=timeout, return_when='FIRST_COMPLETED')
            # cleanup
            for task in tasks:
                try:
                    task.result(timeout=0)
                except concurrent.futures.TimeoutError:
                    pass
    

    Testing the function

    import threading
    import time
    from datetime import datetime, timedelta
    
    def bomb(myevent, sleep_s):
        '''set event after sleep_s seconds'''
        with lock:
            print('explodes in ', datetime.now() + timedelta(seconds=sleep_s))
        time.sleep(sleep_s)
        myevent.set()
        with lock:
            print('BOOM!')
    
    lock = threading.RLock()  # so prints don't get jumbled
    a = threading.Event()
    b = threading.Event()
    
    t_pool = ThreadPoolExecutor(max_workers=2)
    
    threading.Thread(target=bomb, args=(event1, 5), daemon=True).start()
    threading.Thread(target=bomb, args=(event2, 120), daemon=True).start()
    
    with lock:
        print('1 second timeout, no ThreadPool', datetime.now())
    
    wait_for_either([a, b], timeout=1)
    
    with lock:
        print('wait_event_or done', datetime.now())
        print('=' * 15)
    
    with lock:
        print('wait for event1', datetime.now())
    
    wait_for_either([a, b], t_pool=t_pool)
    
    with lock:
        print('wait_event_or done', datetime.now())
    

提交回复
热议问题