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)
Like all modern programming languages, Python also allows you to implement multithreading in your applications.
In a single threaded application, this means everything is blocked while you sleep. In a multithreaded application, only the thread you explicitly 'sleep' will block and the other threads still run within the process.
Generally, Python only uses one thread to execute the set of written statements. This means that in python only one thread will be executed at a time.
Multithreading in Python can be achieved by importing the threading module. Now that you have threading module installed, let us move ahead and do Multithreading in Python.
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()
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With