# Python Concurrent Futures Module

The `concurrent.futures` module provides a high-level interface for asynchronously executing callables. It abstracts the execution of tasks in threads or processes using `ThreadPoolExecutor` and `ProcessPoolExecutor`.

## Importing the Module

```python
import concurrent.futures
```

## Executor Objects

### `ThreadPoolExecutor`

`ThreadPoolExecutor` is an `Executor` subclass that uses a pool of threads to execute calls asynchronously. It is suitable for I/O-bound tasks.

```python
import concurrent.futures
import time

def task(n):
    print(f"Processing {n}")
    time.sleep(1)
    return n * n

with concurrent.futures.ThreadPoolExecutor(max_workers=3) as executor:
    future = executor.submit(task, 5)
    print(f"Result: {future.result()}")
```

### `ProcessPoolExecutor`

`ProcessPoolExecutor` is an `Executor` subclass that uses a pool of processes to execute calls asynchronously. It uses the `multiprocessing` module, which allows it to side-step the Global Interpreter Lock (GIL) but also means that only picklable objects can be executed and returned. It is suitable for CPU-bound tasks.

```python
import concurrent.futures

def square(n):
    return n * n

if __name__ == '__main__':
    with concurrent.futures.ProcessPoolExecutor() as executor:
        results = executor.map(square, [1, 2, 3, 4, 5])
        for result in results:
            print(result)
```

## Submitting Tasks

### `submit()`

The `submit()` method schedules the callable, `fn`, to be executed as `fn(*args, **kwargs)` and returns a `Future` object representing the execution of the callable.

```python
with concurrent.futures.ThreadPoolExecutor() as executor:
    future1 = executor.submit(pow, 323, 1235)
    future2 = executor.submit(pow, 323, 1235)

    print(future1.result())
    print(future2.result())
```

### `map()`

The `map()` method is similar to the built-in `map()` function. It runs the function asynchronously on the iterables.

```python
with concurrent.futures.ThreadPoolExecutor() as executor:
    for result in executor.map(lambda x: x**2, range(10)):
        print(result)
```

## Future Objects

A `Future` instance represents the encapsulation of the asynchronous execution of a callable.

*   `result(timeout=None)`: Return the value returned by the call.
*   `cancel()`: Attempt to cancel the call.
*   `done()`: Return `True` if the call was successfully cancelled or finished running.
*   `add_done_callback(fn)`: Attaches the callable `fn` to the future.

### `as_completed()`

The `as_completed()` function returns an iterator over the `Future` instances (that are possibly created by different Executor instances) that yields futures as they complete (finished or cancelled).

[[programming/python/python]]