Controlling Python threads with threading.Event

Recently, I’ve been working on a Python project which has a third party library that provided some thread callbacks for its services. However, this particular library didn’t offer many interface options other than threading.Event and I needed to control some callbacks of this library. Turns out that although threading.Event is quite simple, it enables you to signal certain events between threads. Let’s see an example of how you can wake up a worker thread thread_one by setting an event on thread_two.

Code Snippet

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
#!/usr/bin/env python
import threading
import time
import logging
formatter = "%(asctime)s - %(name)s (%(threadName)-10s) - %(levelname)s - %(message)s"
logging.basicConfig(level=logging.INFO, format=formatter)
logger = logging.getLogger(__name__)
def thread_one(start_event):
logger.info("started")
start_event.wait()
# will be suspended until start_event is true
logger.info("just woke up")
def thread_two(start_event):
logger.info("started")
# will process something...
logger.info("processing something")
time.sleep(2)
logger.info("finished processing")
logger.info("will wake up thread_one")
start_event.set()
if __name__ == '__main__':
start_event = threading.Event()
t_one = threading.Thread(target=thread_one, args=[start_event]).start()
t_two = threading.Thread(target=thread_two, args=[start_event]).start()

Essentially, when the threading.Event object is instantiated it starts as false, and as soon as you call threading.Event.wait() the thread will wait for the event to become true, which can be set by calling threading.Event.set(). Plus, you can also set a timeout if that’s appropriate for your use case.

Information
For more information, checkout official Python threading.Event docs 1.

So here’s the execution of the previous code snippet:

1
2
3
4
5
6
2017-05-25 21:53:06,851 - __main__ (Thread-1 ) - INFO - started
2017-05-25 21:53:06,852 - __main__ (Thread-2 ) - INFO - started
2017-05-25 21:53:06,852 - __main__ (Thread-2 ) - INFO - processing something
2017-05-25 21:53:08,854 - __main__ (Thread-2 ) - INFO - finished processing
2017-05-25 21:53:08,854 - __main__ (Thread-2 ) - INFO - will wake up thread_one
2017-05-25 21:53:08,854 - __main__ (Thread-1 ) - INFO - just woke up

As you can see, both threads almost started at the same time. thread_two (Thread-2) is processing something and after two seconds (time.sleep(2)), it is supposed to wake up thread_one. As soon as thread_two executes start_event.set() thread_one will wake up immediately. You can notice by the timestamp of the code execution that in fact, thread_two woke up practically immediately after the threading.Event was set.

That’s it. Quite straightforward, but totally handy when that’s all you’ve got to work with. Plus, certainly, this solution is better than a busy-wait loop.

References