Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

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 image 703
kdt Avatar asked Sep 07 '12 12:09

kdt


People also ask

Can two threads run at the same time Python?

Like all modern programming languages, Python also allows you to implement multithreading in your applications.

Does time sleep block all threads?

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.

How many threads can be created simultaneously in Python?

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.

Can we achieve multi threading in Python?

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.


1 Answers

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() 
like image 77
Claudiu Avatar answered Sep 23 '22 03:09

Claudiu