# **Thread Pools in Python**
Thread pools are a high-level abstraction for managing a fixed number of worker threads. They simplify task submission and allow efficient utilization of resources in multi-threaded applications.
---
## **Why Use Thread Pools?**
Thread pools:
- Limit the number of active threads to prevent resource exhaustion.
- Simplify managing and coordinating multiple threads.
- Automatically handle thread creation and destruction.
---
## **Using `ThreadPoolExecutor`**
The `concurrent.futures.ThreadPoolExecutor` provides a simple API for managing thread pools.
### **Example 1: Submitting Tasks**
```python
from concurrent.futures import ThreadPoolExecutor
def task(n):
print(f"Processing {n}")
with ThreadPoolExecutor(max_workers=5) as executor:
executor.submit(task, 1)
executor.submit(task, 2)
executor.submit(task, 3)
```
---
### **Example 2: Using `map` for Multiple Tasks**
The `map` method can process multiple tasks efficiently by distributing them among threads.
```python
from concurrent.futures import ThreadPoolExecutor
def task(n):
print(f"Processing {n}")
with ThreadPoolExecutor(max_workers=3) as executor:
executor.map(task, range(10))
```
---
### **Example 3: Handling Results**
You can retrieve and handle results using `Future` objects.
```python
from concurrent.futures import ThreadPoolExecutor
def task(n):
return n * n
with ThreadPoolExecutor(max_workers=3) as executor:
futures = [executor.submit(task, i) for i in range(5)]
results = [future.result() for future in futures]
print(results)
```
---
### **Example 4: Exception Handling**
Thread pools make it easy to handle exceptions raised during task execution.
```python
from concurrent.futures import ThreadPoolExecutor
def task(n):
if n == 3:
raise ValueError("Example exception")
return n
with ThreadPoolExecutor(max_workers=3) as executor:
futures = [executor.submit(task, i) for i in range(5)]
for future in futures:
try:
print(future.result())
except Exception as e:
print(f"Task raised an exception: {e}")
```
---
## **When to Use Thread Pools**
- For I/O-bound tasks: File operations, network requests, database interactions.
- Not ideal for CPU-bound tasks due to Python’s Global Interpreter Lock (GIL); consider using `ProcessPoolExecutor` for parallelism in such cases.
---
## **Explore Next**
- [[Testing and Debugging Concurrent Programs]]: Tools and techniques to validate concurrent programs.
- [[Concurrency Concepts]]: Overview of threads, processes, and asyncio.
- [[Avoiding Starvation]]: Techniques for fair resource management in thread pools.
---
This note explains how to use thread pools in Python effectively, with practical examples for direct implementation. It’s ready for use in Obsidian.