Python Thread Pool: Efficient Multithreading with ThreadPoolExecutor
Learn how to efficiently manage multiple tasks using a thread pool in Python. The ThreadPoolExecutor class from the concurrent.futures module helps control thread creation and asynchronous task execution, making it ideal for handling multithreading in Python.
What is a Thread Pool?
A thread pool automatically manages a pool of worker threads. Each thread in the pool is called a worker thread and can be reused once its task is completed. A thread pool controls thread creation and task execution, making it efficient for managing multiple tasks.
In Python, the ThreadPoolExecutor
class in the concurrent.futures
module allows asynchronous execution of functions by multiple threads.
Key Classes in concurrent.futures
Module:
- Future Class
- ThreadPoolExecutor Class
- ProcessPoolExecutor Class
The Future Class
The concurrent.futures.Future
class handles asynchronous execution of any callable, such as a function. To get a Future
object, call the submit()
method on an Executor
object.
Important Methods in Future Class:
result(timeout=None)
: Returns the value from the callable, or raises aTimeoutError
if not completed in the specified time.cancel()
: Attempts to cancel the callable. ReturnsTrue
if successful,False
otherwise.cancelled()
: ReturnsTrue
if the callable was successfully cancelled.running()
: ReturnsTrue
if the callable is currently running and cannot be cancelled.done()
: ReturnsTrue
if the callable was successfully cancelled or finished running.
The ThreadPoolExecutor Class
The ThreadPoolExecutor
class represents a pool of worker threads for executing calls asynchronously.
Syntax:
Syntax
concurrent.futures.ThreadPoolExecutor(max_threads)
Example:
Below is an example of using the ThreadPoolExecutor
class:
Example
from concurrent.futures import ThreadPoolExecutor
from time import sleep
def square(numbers):
for val in numbers:
ret = val * val
sleep(1)
print("Number:{} Square:{}".format(val, ret))
def cube(numbers):
for val in numbers:
ret = val * val * val
sleep(1)
print("Number:{} Cube:{}".format(val, ret))
if __name__ == '__main__':
numbers = [1, 2, 3, 4, 5]
executor = ThreadPoolExecutor(4)
thread1 = executor.submit(square, (numbers))
thread2 = executor.submit(cube, (numbers))
print("Thread 1 executed ? :", thread1.done())
print("Thread 2 executed ? :", thread2.done())
sleep(2)
print("Thread 1 executed ? :", thread1.done())
print("Thread 2 executed ? :", thread2.done())
Output
Thread 1 executed ? : False
Thread 2 executed ? : False
Number:1 Square:1
Number:1 Cube:1
Number:2 Square:4
Number:2 Cube:8
Thread 1 executed ? : False
Thread 2 executed ? : False
Number:3 Square:9
Number:3 Cube:27
Number:4 Square:16
Number:4 Cube:64
Number:5 Square:25
Number:5 Cube:125
Thread 1 executed ? : True
Thread 2 executed ? : True