How to Check Task Status in the ThreadPoolExecutor
You can check the status of tasks on a ThreadPoolExecutor in Python by calling running(), done(), and cancelled() on the Future object.
In this tutorial, you will discover how to check the status of tasks submitted to a thread pool.
Let's get started.
Check the Status of Submitted Tasks
The ThreadPoolExecutor in Python provides a pool of reusable threads for executing ad hoc tasks.
You can submit tasks to the thread pool by calling the submit() function and passing in the name of the function you wish to execute on another thread.
Calling the submit() function will return a Future object that allows you to check on the status of the task and get the result from the task once it completes.
After you have submitted tasks, you may want to check on their status.
For example, you may want to check if a task is still running or has been done. If a task is done, you may want to check if it was cancelled.
Use the Future Object to Check Status
You can check the status of tasks submitted to the ThreadPoolExecutor via the task's Future object.
Recall that you will receive a Future object when you submit your task to the thread pool when you call the submit() function.
...
# submit a task to the thread pool
future = executor.submit(work)
The Future object has a number of functions that you can use to check the status of the task; they are as follows:
running(): ReturnsTrueif the task is running,Falseotherwise.done(): ReturnsTrueif the task is done,Falseotherwise.cancelled(): ReturnsTrueif the task was cancelled,Falseotherwise.
A running task will not be done or cancelled.
...
# check if a task is running
running = future.running()
A done task will not be running but may have been cancelled.
...
# check if a task is done
done = future.done()
A cancelled task will not be running and will be done.
...
# check if a task was cancelled
cancelled = future.cancelled()
A task can be cancelled via its future object by calling the cancel() function that returns True if the task was cancelled and False otherwise. Only a task that is not running and not done can be cancelled.
cancel(): Attempts to cancel a task, returnsTrueif cancelled,Falseotherwise.
Now that we know how to check the status of a task, let's look at a worked example.
How to Check the Status of Tasks in a ThreadPoolExecutor
Let's demonstrate how to check the status of a task submitted to the ThreadPoolExecutor.
Task Running and Done Status
First, we can define a simple task that will sleep for a given number of seconds.
# mock task that will sleep for a moment
def work(sleep_time):
sleep(sleep_time)
We can then create a thread pool using the context manager.
...
# create a thread pool
with ThreadPoolExecutor() as executor:
# ...
Next, we can check the status of our task, which we expect to be running and not yet done.
...
# start one thread
future = executor.submit(work, 1)
# confirm that the task is running
print(f'running={future.running()}, done={future.done()}')
We can then wait for the task to complete by calling the wait() module function and passing it a list that contains the single future object.
...
# wait for the task to complete
wait()
Now that the task is complete, we can check the status again. We would expect the task to no longer be running and to be done.
...
# confirm that the task is done
print(f'Future running={future.running()}, done={future.done()}')
Tying this together, the complete example of checking the status of a task is listed below.
# SuperFastPython.com
# check the status of a Future object for task executed by a thread pool
from time import sleep
from concurrent.futures import ThreadPoolExecutor
from concurrent.futures import wait
# mock task that will sleep for a moment
def work(sleep_time):
sleep(sleep_time)
# create a thread pool
with ThreadPoolExecutor() as executor:
# start one thread
future = executor.submit(work, 1)
# confirm that the task is running
print(f'Future running={future.running()}, done={future.done()}')
# wait for the task to complete
wait()
# confirm that the task is done
print(f'Future running={future.running()}, done={future.done()}')
Running the example, we can see that immediately after starting the task that it is marked running and not yet done.
After it has completed, the task is marked as not running and done, as we expected.
Future running=True, done=False
Future running=False, done=True
Task Cancelled Status
We can also demonstrate the status of a task that is cancelled.
First, we can update the example so that the thread pool only creates a single worker thread.
...
# create a thread pool
with ThreadPoolExecutor(1) as executor:
# ...
We can then submit a long-running task that will occupy the single worker thread.
This is required so that we can submit a second task that can be cancelled because it is not yet running.
...
# start a long running task
_ = executor.submit(work, 1)
Next, we can submit a second shorter duration task and check its status.
...
# start a second task
future = executor.submit(work, 0.1)
print(f'running={future.running()}, cancelled={future.cancelled()}, done={future.done()}')
We can then cancel the second task and check its status again.
Note that we can only cancel the second task because it is not yet running.
...
# cancel the second task
was_cancelled = future.cancel()
print(f'Cancelled: {was_cancelled}')
# wait for the second task to complete
wait()
print(f'running={future.running()}, cancelled={future.cancelled()}, done={future.done()}')
Tying this together, the complete example is listed below.
# SuperFastPython.com
# example of checking the status of a cancelled task
from time import sleep
from concurrent.futures import ThreadPoolExecutor
from concurrent.futures import wait
# mock task that will sleep for a moment
def work(sleep_time):
sleep(sleep_time)
# create a thread pool
with ThreadPoolExecutor(1) as executor:
# start a long running task
_ = executor.submit(work, 1)
# start a second task
future = executor.submit(work, 0.1)
print(f'running={future.running()}, cancelled={future.cancelled()}, done={future.done()}')
# cancel the second task
was_cancelled = future.cancel()
print(f'Cancelled: {was_cancelled}')
# wait for the second task to complete
wait()
print(f'running={future.running()}, cancelled={future.cancelled()}, done={future.done()}')
Running the example first creates the thread pool with a single worker thread, then occupies the worker thread with a long running task.
We then submit our second task and check its status. We can see that it is not yet running and is not cancelled or done.
We then cancel the second task, which is reported successfully.
The status of the second task is checked again and we confirm that the task is still not running and was indeed cancelled and is now marked done.
running=False, cancelled=False, done=False
Cancelled: True
running=False, cancelled=True, done=True
Takeaways
You now know how to check the status of tasks submitted to a ThreadPoolExecutor.
If you enjoyed this tutorial, you will love my book: Python ThreadPoolExecutor Jump-Start. It covers everything you need to master the topic with hands-on examples and clear explanations.