# Wait for several tasks (Task.WhenAll, Task.WhenAny)

> Task.WhenAll waits for every task and answers their results in order; Task.WhenAny answers the first task to finish, and the others keep running, as in C# — hand them a CancellationToken to stop them. Task.WaitAll and Task.WaitAny are the same joins written C#'s blocking way. Task.FromResult and Task.CompletedTask are already finished.

<!-- id: function-task-whenall · area: function · stability: stable · html: https://osysharp.com/reference/function/task-whenall/ -->

## Summary        {#summary}
Start several tasks, then wait for them together. `await Task.WhenAll(a, b)` returns when **every** task has finished
and answers their results as an array, in the order you passed them. `await Task.WhenAny(a, b)` returns the **first**
task to finish — `await` that to get its value.

```osy syntax
int[] both  = await Task.WhenAll(Count(x), Count(y));
var  first  = await Task.WhenAny(Ask(primary), Ask(backup));
var  answer = await first;
```

## Signature      {#signature}
```osy syntax
await Task.WhenAll(a, b, …)        // Task<T[]> — every result, in operand order
await Task.WhenAll(tasks)          // …over a List<Task<T>> (or any collection of tasks)
await Task.WhenAny(a, b, …)        // Task<Task<T>> — the first task to finish
Task.WaitAll(a, b, …)              // the WhenAll join, written as a statement
Task.WaitAny(a, b, …)              // int — the index of the first task to finish
Task.FromResult(value)             // a Task<T> already finished with value
Task.FromException(ex)             // a Task already failed with ex (FromException<T> for a Task<T>)
Task.FromCanceled(token)           // a Task already cancelled
Task.CompletedTask                 // a Task already finished
await Task.Yield()                 // accepted; a task already finished
```

## Description    {#description}

### What does WhenAll answer when one fails?   {#whenall-failure}
`Task.WhenAll` waits for **every** task, even after one has failed — then rethrows the first failure, in the order
you passed the tasks. That is C#'s rule: nothing is still running when the error reaches you. Over tasks with no
result (`Task`), it answers nothing.

### Which task does WhenAny pick?   {#whenany}
The first to **finish**, whether it succeeded or failed — as C# answers it. Awaiting the winner gives its value or
rethrows its failure. When several tasks are already finished, the first of them in the order you passed.

### What happens to the tasks that lost?   {#losers}
They **keep running**, as in C#, and the run still waits for them before it ends — work a run started is never left
behind. To stop them, do what C# does: hand each task a `CancellationToken` and cancel it once you have the winner.
A task handed a token stops when it is cancelled — its waits and its outbound calls with it — even if it never reads
the token itself (see [Stop a task (CancellationToken) and complete one by hand (TaskCompletionSource)](https://osysharp.com/reference/function/cancellation/)).

### Are Task.WaitAll and Task.WaitAny blocking?   {#wait}
They are the same joins, written as C# writes a blocking wait: `Task.WaitAll(a, b)` waits for both,
`Task.WaitAny(a, b)` answers the index of the first to finish. Nothing here holds a thread, so neither can deadlock;
`t.Wait()`, `t.Result` and `t.GetAwaiter().GetResult()` are joins in the same way. As in C#, the blocking forms raise
an `AggregateException` over the failure — `Task.WaitAll` over EVERY failure, in operand order — where `await` raises
the first failure itself.

### Can I build the list in a loop?   {#list}
Yes — that is the fan-out over data whose size is known only at run time. Add each started task to a
`List<Task<T>>` and pass the list.

### Can a task wait for a person?   {#waits}
In a workflow body, yes: a function started as a task may await a child workflow run, and `Task.WhenAll` /
`Task.WhenAny` over it hold for as long as that takes — the run parks, and resumes with the results
([Tasks that wait (Task.WhenAll across days)](https://osysharp.com/reference/workflow/tasks-that-wait/)). Outside a workflow a task runs beside its caller from beginning to end.

### Can a race have a timeout?   {#timeout}
`Task.Delay` is a task too, so the C# timeout is written the C# way — race the work against a delay, and see which won.

## Examples       {#examples}
```osy title="a fan-out over a list, then every result at once" test app=function-task-whenall
async Task<int> Score(int n) { return n * n; }

async Task<int> Total(int count) {
  var tasks = new List<Task<int>>();
  for (var i = 1; i <= count; i++) { tasks.Add(Score(i)); }
  var scores = await Task.WhenAll(tasks);
  return scores.Sum();
}
```

```osy title="a race with a timeout: whichever finishes first" test app=function-task-whenall
async Task<string> Slow() {
  await Task.Delay(TimeSpan.FromSeconds(30));
  return "late";
}

async Task<string> WithTimeout() {
  var work = Slow();
  var limit = Task.Delay(TimeSpan.FromSeconds(2));
  var first = await Task.WhenAny(work, limit);
  return first == work ? await work : "timed out";
}
```

```osy title="a race whose loser is stopped with a token" test app=function-task-whenall
async Task<int> Fast() { return 1; }
async Task<int> Patient(CancellationToken token) {
  await Task.Delay(TimeSpan.FromSeconds(30), token);
  return 2;
}

async Task<int> FirstThenStop() {
  var cts = new CancellationTokenSource();
  var winner = await Task.WhenAny(Fast(), Patient(cts.Token));
  cts.Cancel();
  return await winner;
}
```

```osy title="already-finished tasks, for a method that must return one" test app=function-task-whenall
Task<int> Known(int n) { return Task.FromResult(n); }

async Task<int> Sum() {
  await Task.CompletedTask;
  var both = await Task.WhenAll(Known(2), Known(3));
  return both[0] + both[1];
}
```

## See also       {#see-also}
- [async / await and Task](https://osysharp.com/reference/function/async-await/) — starting a task, and what a task may do
- [Wait in place (Task.Delay)](https://osysharp.com/reference/function/task-delay/) — a delay, awaited or raced
- [Stop a task (CancellationToken) and complete one by hand (TaskCompletionSource)](https://osysharp.com/reference/function/cancellation/) — stopping a task with a CancellationToken
- [Tasks that wait (Task.WhenAll across days)](https://osysharp.com/reference/workflow/tasks-that-wait/) — tasks that wait on child workflow runs, across days
- [Parallel legs (start several, then wait for them)](https://osysharp.com/reference/workflow/parallel-legs/) — the same joins over child workflows, with compensation
