Last Updated on September 12, 2022
You can wait on results from a new thread in a number of ways.
Common approaches include, using a sleep, joining the new thread, using an event or wait/notify to signal that results are available, and to share results using a thread-safe queue.
In this tutorial you will discover how to wait for a result from a thread in Python.
Let’s get started.
Need to Wait for Result from a Thread
A thread is a thread of execution in a computer program.
Every Python program has at least one thread of execution called the main thread. Both processes and threads are created and managed by the underlying operating system.
Sometimes we may need to create additional threads in our program in order to execute code concurrently.
Python provides the ability to create and manage new threads via the threading module and the threading.Thread class.
You can learn more about Python threads in the guide:
In concurrent programming, we often may need for one thread to wait for a result from another thread.
For example, the main thread waiting on a result from a new thread.
This could be for many reasons, such as:
- The new thread is performing a sub-task required by the main thread.
- The new thread is retrieving data from an external resource like a file or socket.
- The new thread is collating or calculating data.
How can one thread wait on a result from another thread?
Run loops using all CPUs, download your FREE book to learn how.
How to Wait for a Result from a Thread
It is common to use a new thread to perform a sub-task required by another thread.
This is often a task that involves blocking function calls, such as reading or writing a file, a socket, or similar external resource.
Python threads do not provide a direct method to get results from a new thread to a waiting thread. Instead indirect methods can be used, such as:
- Use instance variables on an extended threading.Thread.
- Use a queue.Queue to share a result between threads.
- Use a global variable to share a result between threads.
You can learn more about how to return a result from a thread in this tutorial:
Before we can get the result from the new thread, the new thread must prepare the result. This means that the other thread must wait until the result is prepared and made available.
There are many ways for one to wait for a result from another thread.
Five common approaches include:
- Use a Sleep: Use a busy-wait loop with a call to time.sleep().
- Join the Thread: Call join() to wait for the new thread to terminate.
- Use an Event: Wait on a threading.Event to be set.
- Use a Wait/Notify: Wait on a threading.Condition to be notified about each result.
- Use a Queue: Wait on a queue.Queue for results to arrive.
Let’s take a closer look at each approach in turn.
Wait for a Result With Sleep
We can wait for a result using sleep.
Specifically, the waiting thread can call the time.sleep() function and specify a number of seconds to wait.
The thread will then block until the number of seconds has elapsed, before checking whether the new thread has completed and returned a result.
This could be performed in a loop, where each iteration the waiting thread checks if the result is ready and available. If so, the thread can break the loop and use the result, otherwise it can repeat the waiting process.
For example:
1 2 3 4 5 |
... # loop until the result is available while not is_result_availble(): # block for a moment sleep(1) |
This is called a busy wait loop as the waiting thread will keep itself busy checking for the result while waiting.
You can learn more about busy waiting here:
It is generally an inefficient approach to waiting for a result.
Nevertheless, if the waiting thread has other tasks to perform while waiting, this may be a preferred method.
Free Python Threading Course
Download your FREE threading PDF cheat sheet and get BONUS access to my free 7-day crash course on the threading API.
Discover how to use the Python threading module including how to create and start new threads and how to use a mutex locks and semaphores
Waiting for a Result By Join the Thread
We can wait for a result by joining the thread.
Specifically, the waiting thread can join the new thread. This will block the waiting thread until the new thread has terminated.
The waiting thread will then unblock and can then retrieve the result.
For example:
1 2 3 4 5 |
... # block until the new thread has terminated thread.join() # get the result from the new thread # ... |
The waiting thread will not consume any resources while waiting, which is desirable.
You can learn more about joining threads in this tutorial:
The downside of joining the new thread is that the waiting thread must wait until the new thread terminates. This might be a long time after the desired result is available if the new thread is performing many sub-tasks.
Nevertheless, if the single task of the new thread is to prepare a result for the waiting thread, joining the thread might be a preferred method.
Overwhelmed by the python concurrency APIs?
Find relief, download my FREE Python Concurrency Mind Maps
Wait for a Result With an Event
We can use an event to signal that a result is available.
Specifically, the waiting thread can wait for the event to be set, and the new thread can set the event to true once the result is available.
This can be achieved with a threading.Event instance that provides a thread-safe boolean variable designed to be shared between threads.
The waiting thread can wait for the event to be set via a call to the wait() function.
For example:
1 2 3 4 5 |
... # wait for the event to be set event.wait() # get the result from the new thread ... |
The new thread responsible for preparing the result can then set the event once the result is available.
For example:
1 2 3 |
... # set the event event.set() |
The waiting thread will not consume any resource while waiting for the result.
Unlike joining the thread, using an event does not require that the waiting thread block until the new thread has terminated.
You can learn more about event objects in this tutorial:
The downside of an event is that it may be a single use trigger for new results.
Nevertheless, it is an efficient and effective method for a new thread to signal that a single result is available.
Wait for a Result With Wait/Notify
We can use wait/notify to signal that a result or results are available from a new thread.
Specifically, the new thread can notify waiting threads that a result is available. The waiting thread can explicitly wait to be notified by the new thread. This mechanism may then be reused multiple times if there is more than one result to be made available.
This can be achieved using a threading.Condition.
The waiting thread can wait to be notified by calling the wait() function on the condition.
For example:
1 2 3 4 5 |
... # wait to be notified about the result condition.wait() # get the result ... |
The new thread can call the notify() function to signal to the waiting thread that a result is available.
For example:
1 2 3 |
... # notify the waiting thread that a result is available condition.notify() |
If there are multiple threads waiting for a result, then the new thread can notify them all via the notify_all() function.
1 2 3 |
... # notify all waiting threads that a result is available. condition.notify_all() |
If multiple results are to be made available, then the waiting read may be notified each time, for example:
1 2 3 4 5 6 7 |
... # prepare results while more_results(): # prepare a result ... # notify the waiting thread condition.notify() |
The waiting thread will not consume any resource while waiting for the result.
Unlike using an event, the waiting thread may reuse the wait/notify mechanism and seek to be notified each time a new result is made available.
You can learn more about the condition object in this tutorial:
One downside of using wait/notify with a threading condition is that it is possible for the waiting thread to miss notification messages. This is a type of timing-based race condition.
You can learn more about this type of race condition here:
Nevertheless, the wait/notify mechanism can be an efficient approach for a new thread to notify one or more waiting threads about multiple results.
Wait for a Result With a Queue
We can wait for results via a thread-safe queue.
Specifically, the new thread can share new results by putting them in a queue data structure as they are available. The waiting thread can wait on the queue for results to arrive and consume them as they do.
This can be achieved using a thread-safe queue data structure such as the queue.Queue class or the queue.SimpleQueue class.
The waiting thread can wait on a queue instance for results by calling the get() function.
This function will block until a result is available.
For example:
1 2 3 |
... # wait for a result result = queue.get() |
If multiple results are expected, then the call to get a result can be performed in a loop.
For example:
1 2 3 4 5 |
... # get all results while not done(): # wait for a result result = queue.get() |
The new thread will share results if they are made available by calling the put() function on the queue.
For example:
1 2 3 |
... # make a result available queue.put(result) |
This will notify the waiting thread that it can wake-up and consume a result.
Again, the new thread can place multiple results on the queue if needed, such as in a loop.
For example:
1 2 3 4 5 |
... # prepare all results while not done(): # share result with waiting thread queue.put(result) |
The waiting thread will not consume any resource while waiting for the result.
Like using a condition, the queue allows multiple results to be shared. It may also allow multiple threads to consume results, as well as multiple threads to generate results, as long as they all have access to the same queue instance.
Unlike the condition, the waiting thread will not miss a new result due to a timing race condition, as new results will sit in the queue data structure until they are consumed.
The queue approach to waiting for results may be preferred if there is a large volume of results to be shared. It may also be stacked into a pipeline if there are multiple threads producing and consuming results in a series.
Further Reading
This section provides additional resources that you may find helpful.
Python Threading Books
- Python Threading Jump-Start, Jason Brownlee (my book!)
- Threading API Interview Questions
- Threading Module API Cheat Sheet
I also recommend specific chapters in the following books:
- Python Cookbook, David Beazley and Brian Jones, 2013.
- See: Chapter 12: Concurrency
- Effective Python, Brett Slatkin, 2019.
- See: Chapter 7: Concurrency and Parallelism
- Python in a Nutshell, Alex Martelli, et al., 2017.
- See: Chapter: 14: Threads and Processes
Guides
- Python Threading: The Complete Guide
- Python ThreadPoolExecutor: The Complete Guide
- Python ThreadPool: The Complete Guide
APIs
References
Takeaways
You now know how to wait for a result from a thread.
Do you have any questions?
Ask your questions in the comments below and I will do my best to answer.
Photo by Jeremy Bishop on Unsplash
Do you have any questions?