Swiftorial Logo
Home
Swift Lessons
Matchups
CodeSnaps
Tutorials
Career
Resources

Concurrent.futures Module in Python

1. Introduction

The concurrent.futures module in Python provides a high-level interface for asynchronously executing callables using threads or processes. It simplifies the task of concurrent programming.

This module is especially useful for I/O-bound and CPU-bound tasks, allowing developers to leverage multi-core processors and improve performance.

2. Key Concepts

  • Executor: An abstract class that provides methods to execute calls asynchronously.
  • ThreadPoolExecutor: An implementation of Executor that uses a pool of threads.
  • ProcessPoolExecutor: An implementation of Executor that uses a pool of processes.
  • Future: A placeholder for a result that hasn’t been computed yet.

3. Usage

3.1. Using ThreadPoolExecutor

The ThreadPoolExecutor is suitable for I/O-bound tasks. Below is a simple example:

from concurrent.futures import ThreadPoolExecutor
import time

def fetch_data(seconds):
    time.sleep(seconds)
    return f"Fetched data after {seconds} seconds"

with ThreadPoolExecutor() as executor:
    futures = [executor.submit(fetch_data, i) for i in range(1, 4)]
    for future in futures:
        print(future.result())

3.2. Using ProcessPoolExecutor

The ProcessPoolExecutor is suitable for CPU-bound tasks. Below is an example:

from concurrent.futures import ProcessPoolExecutor
import math

def compute_factorial(n):
    return math.factorial(n)

with ProcessPoolExecutor() as executor:
    results = executor.map(compute_factorial, range(1, 6))
    for result in results:
        print(result)

4. Best Practices

  • Always use context managers (with statement) when creating executors to ensure proper clean-up.
  • Limit the number of workers to the number of available CPU cores for CPU-bound tasks.
  • Handle exceptions from futures to avoid crashing the program.
  • Avoid sharing mutable state between threads or processes.

5. FAQ

What is the difference between ThreadPoolExecutor and ProcessPoolExecutor?

ThreadPoolExecutor is better suited for I/O-bound tasks where tasks spend a lot of time waiting for external resources. ProcessPoolExecutor is more appropriate for CPU-bound tasks that require heavy computation.

Can I use both executors in the same application?

Yes, you can use both executors in the same application based on the specific requirements of your tasks.

How do I handle exceptions in futures?

You can call future.exception() to retrieve any exception that occurred during the execution of the submitted callable.