> ## Documentation Index
> Fetch the complete documentation index at: https://docs.outerproduct.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Call fanouts

> Run a function across multiple inputs with client.map().

A common pattern in a Run is to apply the same function independently to many inputs. The  `client.map()` method provides a succinct way to express this fanout.

## Calling client.map()

Inside a Run, `client.map()` submits one child Call per input. From local code, it submits one separate Run per input. In either case, it uses the same execution settings for each submission and returns an iterator that yields results in input order. You can consume those results without calling `.wait()` on individual handles.

In the example below, each batch produces one Call to `sum_batch`, with the batch passed as its `values` argument. Here, the Run contains one root Call and three child Calls.

```python theme={null}
from collections.abc import Iterator

import outerproduct as op


def sum_batch(batch: list[int]) -> int:
    return sum(batch)


def sum_batches(client, batches: list[list[int]]) -> int:
    results: Iterator[int] = client.map(
        sum_batch,
        batches,
        image=image,
        name="Sum batch",
    )
    # results yields 6, 15, 24 for the batches below.
    return sum(results)


if __name__ == "__main__":
    run: op.Run[int] | op.Call[int] = client.run(
        fn=sum_batches,
        args=([[1, 2, 3], [4, 5, 6], [7, 8, 9]],),
        image=image,
    )

    print(run.wait())  # 45
```

`name` is optional. If omitted, each display label defaults to the function's qualified name (such as `sum_batch` here). If provided, the same label is used for every Run or child Call submitted by `map()`. Within a Run, the UI adds each child Call's number among its parent's children, such as `Sum batch #1`, `Sum batch #2`, and `Sum batch #3` in this example. From local code, each item is a separate Run with the same label.

## Pass multiple iterables with map()

You can pass multiple iterables to `client.map()`. Each iterable supplies one positional argument. In this example, the first Call receives 1 and 10, and the second receives 2 and 20:

```python theme={null}
from collections.abc import Iterator


def add(_client, x: int, y: int) -> int:
    return x + y


if __name__ == "__main__":
    results: Iterator[int] = client.map(add, [1, 2], [10, 20], image=image)

    # The for loop iterates over results: it asks for one result at a time.
    for result in results:
        print(result)  # Prints 11, then 22.
```

If the iterables have different lengths, `map()` makes Calls only for the positions present in every iterable.

## Read results from map()

Iterate over `results` to get each answer:

```python theme={null}
from collections.abc import Iterator

results: Iterator[int] = client.map(add, [1, 2], [10, 20], image=image)

for result in results:
    print(result)  # Prints 11, then 22.
```

When the `for` loop begins, `map()` submits all the invocations. They may run at the same time, but their results arrive in input order. If an invocation fails, the loop raises its error when it reaches that result.

Stopping the loop early does not cancel work already submitted.

## Durability

When used within a Run, `client.map()` creates parallel child Calls. So, if the parent function retries, completed child results are reused. See [Retries & Durability](https://docs.outerproduct.com/retries-and-durability.md) for more on how retries behave within a single Run.

However, when `client.map()` is used outside a Run, each input creates a separate Run with its own retries and durability boundary. So, calling `client.map()` again from local code starts new Runs for every input, including inputs that previously completed successfully.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.