# Source: https://fastcore.fast.ai/parallel.html.md

# Parallel


<!-- WARNING: THIS FILE WAS AUTOGENERATED! DO NOT EDIT! -->

``` python
from fastcore.test import *
from nbdev.showdoc import *
from fastcore.nb_imports import *
```

------------------------------------------------------------------------

<a
href="https://github.com/AnswerDotAI/fastcore/blob/main/fastcore/parallel.py#L25"
target="_blank" style="float:right; font-size:smaller">source</a>

### threaded

``` python

def threaded(
    process:bool=False
):

```

*Run `f` in a `Thread` (or `Process` if `process=True`), and returns it*

``` python
@threaded
def _1():
    time.sleep(0.05)
    print("second")
    return 5

@threaded
def _2():
    time.sleep(0.01)
    print("first")

a = _1()
_2()
time.sleep(0.1)
```

    first
    second

After the thread is complete, the return value is stored in the `result`
attr.

``` python
a.result
```

    5

------------------------------------------------------------------------

<a
href="https://github.com/AnswerDotAI/fastcore/blob/main/fastcore/parallel.py#L46"
target="_blank" style="float:right; font-size:smaller">source</a>

### startthread

``` python

def startthread(
    f
):

```

*Like [`threaded`](https://fastcore.fast.ai/parallel.html#threaded), but
start thread immediately*

``` python
@startthread
def _():
    time.sleep(0.05)
    print("second")

@startthread
def _():
    time.sleep(0.01)
    print("first")

time.sleep(0.1)
```

    first
    second

------------------------------------------------------------------------

<a
href="https://github.com/AnswerDotAI/fastcore/blob/main/fastcore/parallel.py#L51"
target="_blank" style="float:right; font-size:smaller">source</a>

### startproc

``` python

def startproc(
    f
):

```

*Like `threaded(True)`, but start Process immediately*

``` python
@startproc
def _():
    time.sleep(0.05)
    print("second")

@startproc
def _():
    time.sleep(0.01)
    print("first")

time.sleep(0.1)
```

    first
    second

------------------------------------------------------------------------

<a
href="https://github.com/AnswerDotAI/fastcore/blob/main/fastcore/parallel.py#L67"
target="_blank" style="float:right; font-size:smaller">source</a>

### parallelable

``` python

def parallelable(
    param_name, num_workers, f:NoneType=None
):

```

------------------------------------------------------------------------

<a
href="https://github.com/AnswerDotAI/fastcore/blob/main/fastcore/parallel.py#L76"
target="_blank" style="float:right; font-size:smaller">source</a>

#### ThreadPoolExecutor

``` python

def ThreadPoolExecutor(
    max_workers:int=4, on_exc:builtin_function_or_method=print, pause:int=0, kwargs:VAR_KEYWORD
):

```

*Same as Python’s ThreadPoolExecutor, except can pass `max_workers==0`
for serial execution*

------------------------------------------------------------------------

<a
href="https://github.com/AnswerDotAI/fastcore/blob/main/fastcore/parallel.py#L95"
target="_blank" style="float:right; font-size:smaller">source</a>

#### ProcessPoolExecutor

``` python

def ProcessPoolExecutor(
    max_workers:int=4, on_exc:builtin_function_or_method=print, pause:int=0, mp_context:NoneType=None,
    initializer:NoneType=None, initargs:tuple=(), max_tasks_per_child:NoneType=None
):

```

*Same as Python’s ProcessPoolExecutor, except can pass `max_workers==0`
for serial execution*

------------------------------------------------------------------------

<a
href="https://github.com/AnswerDotAI/fastcore/blob/main/fastcore/parallel.py#L121"
target="_blank" style="float:right; font-size:smaller">source</a>

### parallel

``` python

def parallel(
    f, items, args:VAR_POSITIONAL, n_workers:int=4, total:NoneType=None, progress:NoneType=None, pause:int=0,
    method:NoneType=None, threadpool:bool=False, timeout:NoneType=None, chunksize:int=1, kwargs:VAR_KEYWORD
):

```

*Applies `func` in parallel to `items`, using `n_workers`*

``` python
inp,exp = range(50),range(1,51)

test_eq(parallel(_add_one, inp, n_workers=2), exp)
test_eq(parallel(_add_one, inp, threadpool=True, n_workers=2), exp)
test_eq(parallel(_add_one, inp, n_workers=1, a=2), range(2,52))
test_eq(parallel(_add_one, inp, n_workers=0), exp)
test_eq(parallel(_add_one, inp, n_workers=0, a=2), range(2,52))
```

Use the `pause` parameter to ensure a pause of `pause` seconds between
processes starting. This is in case there are race conditions in
starting some process, or to stagger the time each process starts, for
example when making many requests to a webserver. Set `threadpool=True`
to use
[`ThreadPoolExecutor`](https://fastcore.fast.ai/parallel.html#threadpoolexecutor)
instead of
[`ProcessPoolExecutor`](https://fastcore.fast.ai/parallel.html#processpoolexecutor).

``` python
from datetime import datetime
```

``` python
def print_time(i): 
    time.sleep(random.random()/1000)
    print(i, datetime.now())

parallel(print_time, range(5), n_workers=2, pause=0.25);
```

    0 2026-01-29 10:59:46.704165
    1 2026-01-29 10:59:46.954594
    2 2026-01-29 10:59:47.204557
    3 2026-01-29 10:59:47.455629
    4 2026-01-29 10:59:47.707717

------------------------------------------------------------------------

<a
href="https://github.com/AnswerDotAI/fastcore/blob/main/fastcore/parallel.py#L145"
target="_blank" style="float:right; font-size:smaller">source</a>

### parallel_async

``` python

def parallel_async(
    f, items, args:VAR_POSITIONAL, n_workers:int=16, timeout:NoneType=None, chunksize:int=1,
    on_exc:builtin_function_or_method=print, kwargs:VAR_KEYWORD
):

```

*Applies `f` to `items` in parallel using asyncio and a semaphore to
limit concurrency.*

``` python
import asyncio
```

``` python
async def print_time_async(i): 
    wait = random.random()
    await asyncio.sleep(wait)
    print(i, datetime.now(), wait)

await parallel_async(print_time_async, range(6), n_workers=3);
```

    0 2026-01-29 10:59:48.007998 0.21615721710303581
    3 2026-01-29 10:59:48.027639 0.018363443750668673
    2 2026-01-29 10:59:48.487320 0.6952425451756079
    1 2026-01-29 10:59:48.550808 0.7519131063729974
    5 2026-01-29 10:59:48.703458 0.21434694863260173
    4 2026-01-29 10:59:48.914600 0.8860713333269471

------------------------------------------------------------------------

<a
href="https://github.com/AnswerDotAI/fastcore/blob/main/fastcore/parallel.py#L160"
target="_blank" style="float:right; font-size:smaller">source</a>

### run_procs

``` python

def run_procs(
    f, f_done, args
):

```

*Call `f` for each item in `args` in parallel, yielding `f_done`*

------------------------------------------------------------------------

<a
href="https://github.com/AnswerDotAI/fastcore/blob/main/fastcore/parallel.py#L175"
target="_blank" style="float:right; font-size:smaller">source</a>

### parallel_gen

``` python

def parallel_gen(
    cls, items, n_workers:int=4, kwargs:VAR_KEYWORD
):

```

*Instantiate `cls` in `n_workers` procs & call each on a subset of
`items` in parallel.*

``` python
# class _C:
#     def __call__(self, o): return ((i+1) for i in o)

# items = range(5)

# res = L(parallel_gen(_C, items, n_workers=0))
# idxs,dat1 = zip(*res.sorted(itemgetter(0)))
# test_eq(dat1, range(1,6))

# res = L(parallel_gen(_C, items, n_workers=3))
# idxs,dat2 = zip(*res.sorted(itemgetter(0)))
# test_eq(dat2, dat1)
```

`cls` is any class with `__call__`. It will be passed `args` and
`kwargs` when initialized. Note that `n_workers` instances of `cls` are
created, one in each process. `items` are then split in `n_workers`
batches and one is sent to each `cls`. The function then returns a
generator of tuples of item indices and results.

``` python
class TestSleepyBatchFunc:
    "For testing parallel processes that run at different speeds"
    def __init__(self): self.a=1
    def __call__(self, batch):
        for k in batch:
            time.sleep(random.random()/4)
            yield k+self.a

x = np.linspace(0,0.99,20)

res = L(parallel_gen(TestSleepyBatchFunc, x, n_workers=2))
test_eq(res.sorted().itemgot(1), x+1)
```

<style>
    progress { appearance: none; border: none; border-radius: 4px; width: 300px;
        height: 20px; vertical-align: middle; background: #e0e0e0; }
&#10;    progress::-webkit-progress-bar { background: #e0e0e0; border-radius: 4px; }
    progress::-webkit-progress-value { background: #2196F3; border-radius: 4px; }
    progress::-moz-progress-bar { background: #2196F3; border-radius: 4px; }
&#10;    progress:not([value]) {
        background: repeating-linear-gradient(45deg, #7e7e7e, #7e7e7e 10px, #5c5c5c 10px, #5c5c5c 20px); }
&#10;    progress.progress-bar-interrupted::-webkit-progress-value { background: #F44336; }
    progress.progress-bar-interrupted::-moz-progress-value { background: #F44336; }
    progress.progress-bar-interrupted::-webkit-progress-bar { background: #F44336; }
    progress.progress-bar-interrupted::-moz-progress-bar { background: #F44336; }
    progress.progress-bar-interrupted { background: #F44336; }    
&#10;    table.fastprogress { border-collapse: collapse; margin: 1em 0; font-size: 0.9em; }
    table.fastprogress th, table.fastprogress td { padding: 8px 12px; border: 1px solid #ddd; text-align: left; }
    table.fastprogress thead tr { background: #f8f9fa; font-weight: bold; }
    table.fastprogress tbody tr:nth-of-type(even) { background: #f8f9fa; }
</style>

``` python
# #|hide
# from subprocess import Popen, PIPE
# # test num_workers > 0 in scripts works when python process start method is spawn
# process = Popen(["python", "parallel_test.py"], stdout=PIPE)
# _, err = process.communicate(timeout=10)
# exit_code = process.wait()
# test_eq(exit_code, 0)
```