Header menu logo FSharp.Control.AsyncSeq

Binder

Consuming Asynchronous Sequences

All AsyncSeq<'T> values are lazy — they only produce elements when actively consumed. This document covers the full range of consumption patterns, from iterating with a side effect to collecting into an array, searching for an element and computing aggregate values.

open FSharp.Control

let oneThenTwo = asyncSeq {
    yield 1
    do! Async.Sleep 1000
    yield 2
}

Iterating with a For Loop

Inside any async { ... } computation, you can iterate an AsyncSeq with a plain for loop. The loop body may contain let! and do! bindings just like the rest of the async block:

async {
    for x in oneThenTwo do
        printfn "Got %d" x
} |> Async.RunSynchronously

This is the most natural way to consume a sequence when you already have an async context, such as an application entry point or an async test.


iter and iterAsync

AsyncSeq.iter applies a synchronous action to every element and returns Async<unit>:

let numbers = asyncSeq { yield! [ 1 .. 5 ] }

let printAll : Async<unit> =
    numbers |> AsyncSeq.iter (printfn "item: %d")

AsyncSeq.iterAsync does the same but the action returns Async<unit>, which is awaited before the next element is consumed. This makes it ideal for actions that themselves do IO — such as writing to a database or calling an API:

let processItem (n: int) : Async<unit> =
    async { printfn "processing %d" n }

let processAll : Async<unit> =
    numbers |> AsyncSeq.iterAsync processItem

iteri and iteriAsync

AsyncSeq.iteri and AsyncSeq.iteriAsync are the same but also pass a zero-based integer index to the action, useful for logging progress or tagging elements:

let printIndexed : Async<unit> =
    numbers |> AsyncSeq.iteri (fun i n -> printfn "[%d] %d" i n)

iterAsyncParallel

AsyncSeq.iterAsyncParallel processes elements concurrently — the action for each element is started as soon as the element is available, without waiting for the previous action to finish. Use this when the actions are independent and you want maximum throughput:

let processAllParallel : Async<unit> =
    numbers |> AsyncSeq.iterAsyncParallel processItem

AsyncSeq.iterAsyncParallelThrottled is the same but limits the number of concurrent actions:

let processThrottled : Async<unit> =
    numbers |> AsyncSeq.iterAsyncParallelThrottled 4 processItem

Folding

AsyncSeq.fold accumulates a state over all elements using a synchronous folder function. It is the most general consumption primitive — all other aggregations can be implemented with it:

let sum : Async<int> =
    numbers |> AsyncSeq.fold (fun acc n -> acc + n) 0

AsyncSeq.foldAsync is the same but the folder returns Async<'State>, for cases where accumulating a value requires async work:

let asyncSum : Async<int> =
    numbers |> AsyncSeq.foldAsync (fun acc n -> async { return acc + n }) 0

reduceAsync

AsyncSeq.reduceAsync is a fold without an explicit seed — it uses the first element as the initial state. It raises InvalidOperationException on an empty sequence:

let words = asyncSeq { yield! [ "F#"; "is"; "great" ] }

let sentence : Async<string> =
    words |> AsyncSeq.reduceAsync (fun acc w -> async { return acc + " " + w })

Searching

pick and tryPick

AsyncSeq.pick applies a chooser function to each element and returns the first Some result, raising KeyNotFoundException if the sequence is exhausted without a match:

let firstEven : Async<int> =
    numbers |> AsyncSeq.pick (fun n -> if n % 2 = 0 then Some n else None)

AsyncSeq.tryPick is the safe variant — it returns Async<'T option> and returns None instead of raising when there is no match:

let maybeFirstOver100 : Async<int option> =
    numbers |> AsyncSeq.tryPick (fun n -> if n > 100 then Some n else None)

AsyncSeq.pickAsync and AsyncSeq.tryPickAsync accept choosers that return Async<_ option>, for cases where the matching decision requires async IO.

exists and forall

AsyncSeq.exists returns true as soon as it finds an element satisfying the predicate, and short-circuits consumption at that point. AsyncSeq.forall returns false as soon as it finds an element that does not satisfy the predicate:

let hasEven  : Async<bool> = numbers |> AsyncSeq.exists (fun n -> n % 2 = 0)
let allSmall : Async<bool> = numbers |> AsyncSeq.forall (fun n -> n < 100)

AsyncSeq.existsAsync and AsyncSeq.forallAsync accept async predicates.

head, last and firstOrDefault

AsyncSeq.head returns the first element, raising if the sequence is empty. AsyncSeq.firstOrDefault returns a default value for empty sequences. AsyncSeq.last and AsyncSeq.lastOrDefault do the same for the final element:

let strings = asyncSeq { yield! [ "hello"; "world" ] }

let firstWord : Async<string> = AsyncSeq.head strings
let lastWord  : Async<string> = AsyncSeq.last strings
let safeFirst : Async<string> = AsyncSeq.firstOrDefault "none" strings

Collecting to a Collection

The toArrayAsync and toListAsync functions consume the entire sequence and materialise it into an F# array or list. These are useful when you need random access or must pass the results to code that expects a concrete collection:

let asArray : Async<int[]>   = numbers |> AsyncSeq.toArrayAsync
let asList  : Async<int list> = numbers |> AsyncSeq.toListAsync

toArraySynchronously and toListSynchronously do the same without wrapping in Async — they block the calling thread until the sequence is exhausted. Only use these outside of async contexts, e.g. in test code or scripts:

let syncArray : int[] = numbers |> AsyncSeq.toArraySynchronously

Aggregation

length

AsyncSeq.length counts the elements, returning Async<int64>:

let count : Async<int64> = numbers |> AsyncSeq.length

sumBy and sumByAsync

AsyncSeq.sumBy projects each element to a numeric type and sums the results:

let sumOfSquares : Async<int> =
    numbers |> AsyncSeq.sumBy (fun n -> n * n)

AsyncSeq.sumByAsync is the same when the projection needs to perform async work:

let fetchScore (n: int) : Async<float> =
    async { return float n * 0.5 } // placeholder

let totalScore : Async<float> =
    numbers |> AsyncSeq.sumByAsync fetchScore

averageBy and averageByAsync

AsyncSeq.averageBy computes the arithmetic mean of a projected value:

let meanSquare : Async<float> =
    numbers |> AsyncSeq.averageBy (fun n -> float (n * n))

AsyncSeq.averageByAsync accepts an async projection:

let meanScore : Async<float> =
    numbers |> AsyncSeq.averageByAsync fetchScore

countBy

AsyncSeq.countBy counts how many elements share each key, returning an array of (key, count) pairs:

let digitParity : Async<(string * int) array> =
    numbers |> AsyncSeq.countBy (fun n -> if n % 2 = 0 then "even" else "odd")

AsyncSeq.countByAsync accepts an async projection when computing the key requires IO.

Multiple items
namespace FSharp

--------------------
namespace Microsoft.FSharp
Multiple items
namespace FSharp.Control

--------------------
namespace Microsoft.FSharp.Control
val oneThenTwo: AsyncSeq<int>
val asyncSeq: AsyncSeq.AsyncSeqBuilder
<summary> Builds an asynchronous sequence using the computation builder syntax </summary>
Multiple items
type Async = static member AsBeginEnd: computation: ('Arg -> Async<'T>) -> ('Arg * AsyncCallback * objnull -> IAsyncResult) * (IAsyncResult -> 'T) * (IAsyncResult -> unit) static member AwaitEvent: event: IEvent<'Del,'T> * ?cancelAction: (unit -> unit) -> Async<'T> (requires delegate and 'Del :> Delegate) static member AwaitIAsyncResult: iar: IAsyncResult * ?millisecondsTimeout: int -> Async<bool> static member AwaitTask: task: Task<'T> -> Async<'T> + 1 overload static member AwaitWaitHandle: waitHandle: WaitHandle * ?millisecondsTimeout: int -> Async<bool> static member CancelDefaultToken: unit -> unit static member Catch: computation: Async<'T> -> Async<Choice<'T,exn>> static member Choice: computations: Async<'T option> seq -> Async<'T option> static member FromBeginEnd: beginAction: (AsyncCallback * objnull -> IAsyncResult) * endAction: (IAsyncResult -> 'T) * ?cancelAction: (unit -> unit) -> Async<'T> + 3 overloads static member FromContinuations: callback: (('T -> unit) * (exn -> unit) * (OperationCanceledException -> unit) -> unit) -> Async<'T> ...

--------------------
type Async<'T>
static member Async.Sleep: dueTime: System.TimeSpan -> Async<unit>
static member Async.Sleep: millisecondsDueTime: int -> Async<unit>
val async: AsyncBuilder
val x: int
val printfn: format: Printf.TextWriterFormat<'T> -> 'T
static member Async.RunSynchronously: computation: Async<'T> * ?timeout: int * ?cancellationToken: System.Threading.CancellationToken -> 'T
val numbers: AsyncSeq<int>
val printAll: Async<unit>
type unit = Unit
Multiple items
module AsyncSeq from FSharp.Control

--------------------
type AsyncSeq<'T> = System.Collections.Generic.IAsyncEnumerable<'T>
<summary> An asynchronous sequence; equivalent to System.Collections.Generic.IAsyncEnumerable&lt;'T&gt;. Use the asyncSeq { ... } computation expression to create values, and the AsyncSeq module for combinators. </summary>
val iter: action: ('T -> unit) -> source: AsyncSeq<'T> -> Async<unit>
<summary> Iterates over the input sequence and calls the specified function for every value. </summary>
val processItem: n: int -> Async<unit>
val n: int
Multiple items
val int: value: 'T -> int (requires member op_Explicit)

--------------------
type int = int32

--------------------
type int<'Measure> = int
val processAll: Async<unit>
val iterAsync: action: ('T -> Async<unit>) -> source: AsyncSeq<'T> -> Async<unit>
<summary> Iterates over the input sequence and calls the specified asynchronous function for every value. The input sequence will be asked for the next element after the processing of an element completes. </summary>
val printIndexed: Async<unit>
val iteri: action: (int -> 'T -> unit) -> source: AsyncSeq<'T> -> Async<unit>
<summary> Iterates over the input sequence and calls the specified function for every value, passing along the index of that element. </summary>
val i: int
val processAllParallel: Async<unit>
val iterAsyncParallel: action: ('T -> Async<unit>) -> source: AsyncSeq<'T> -> Async<unit>
<summary> Iterates over the input sequence and calls the specified asynchronous function for every value. Each action computation is started but not awaited before consuming the next item from the sequence, thereby iterating in parallel. </summary>
val processThrottled: Async<unit>
val iterAsyncParallelThrottled: parallelism: int -> action: ('T -> Async<unit>) -> source: AsyncSeq<'T> -> Async<unit>
<summary> Iterates over the input sequence and calls the specified asynchronous function for every value. Each action computation is started but not awaited before consuming the next item from the sequence, thereby iterating in parallel with a specified degree of parallelism. </summary>
val sum: Async<int>
val fold: folder: ('State -> 'T -> 'State) -> state: 'State -> source: AsyncSeq<'T> -> Async<'State>
<summary> Asynchronously aggregate the elements of the input asynchronous sequence using the specified 'aggregation' function. </summary>
val acc: int
val asyncSum: Async<int>
val foldAsync: folder: ('State -> 'T -> Async<'State>) -> state: 'State -> source: AsyncSeq<'T> -> Async<'State>
<summary> Asynchronously aggregate the elements of the input asynchronous sequence using the specified asynchronous 'aggregation' function. </summary>
val words: AsyncSeq<string>
val sentence: Async<string>
Multiple items
val string: value: 'T -> string

--------------------
type string = System.String
val reduceAsync: reduction: ('T -> 'T -> Async<'T>) -> source: AsyncSeq<'T> -> Async<'T>
<summary> Asynchronously reduce the elements of the input asynchronous sequence using the specified asynchronous 'reduction' function. Raises InvalidOperationException if the sequence is empty. </summary>
val acc: string
val w: string
val firstEven: Async<int>
val pick: chooser: ('T -> 'TResult option) -> source: AsyncSeq<'T> -> Async<'TResult>
<summary> Asynchronously pick a value from a sequence based on the specified chooser function. Raises KeyNotFoundException if the chooser function can't find a matching key. </summary>
union case Option.Some: Value: 'T -> Option<'T>
union case Option.None: Option<'T>
val maybeFirstOver100: Async<int option>
type 'T option = Option<'T>
val tryPick: chooser: ('T -> 'TResult option) -> source: AsyncSeq<'T> -> Async<'TResult option>
<summary> Asynchronously pick a value from a sequence based on the specified chooser function. </summary>
val hasEven: Async<bool>
type bool = System.Boolean
val exists: predicate: ('T -> bool) -> source: AsyncSeq<'T> -> Async<bool>
<summary> Asynchronously determine if there is a value in the sequence for which the predicate returns true </summary>
val allSmall: Async<bool>
val forall: predicate: ('T -> bool) -> source: AsyncSeq<'T> -> Async<bool>
<summary> Asynchronously determine if the predicate returns true for all values in the sequence </summary>
val strings: AsyncSeq<string>
val firstWord: Async<string>
val head: source: AsyncSeq<'T> -> Async<'T>
<summary> Asynchronously returns the first element of the asynchronous sequence. Raises InvalidOperationException if the sequence is empty. </summary>
val lastWord: Async<string>
val last: source: AsyncSeq<'T> -> Async<'T>
<summary> Asynchronously returns the last element of the asynchronous sequence. Raises InvalidOperationException if the sequence is empty, mirroring Seq.last. </summary>
val safeFirst: Async<string>
val firstOrDefault: ``default`` : 'T -> source: AsyncSeq<'T> -> Async<'T>
<summary> Asynchronously returns the first element that was generated by the given asynchronous sequence (or the specified default value). </summary>
val asArray: Async<int array>
val toArrayAsync: source: AsyncSeq<'T> -> Async<'T array>
<summary> Creates an async computation which iterates the AsyncSeq and collects the output into an array. </summary>
val asList: Async<int list>
type 'T list = List<'T>
val toListAsync: source: AsyncSeq<'T> -> Async<'T list>
<summary> Creates an async computation which iterates the AsyncSeq and collects the output into a list. </summary>
val syncArray: int array
val toArraySynchronously: source: AsyncSeq<'T> -> 'T array
<summary> Synchronously iterates the AsyncSeq and collects the output into an array. </summary>
val count: Async<int64>
Multiple items
val int64: value: 'T -> int64 (requires member op_Explicit)

--------------------
type int64 = System.Int64

--------------------
type int64<'Measure> = int64
val length: source: AsyncSeq<'T> -> Async<int64>
<summary> Asynchronously determine the number of elements in the sequence </summary>
val sumOfSquares: Async<int>
val sumBy: projection: ('T -> 'U) -> source: AsyncSeq<'T> -> Async<'U> (requires member (+) and member Zero)
<summary> Asynchronously sum the mapped elements of an asynchronous sequence using a synchronous projection. </summary>
val fetchScore: n: int -> Async<float>
Multiple items
val float: value: 'T -> float (requires member op_Explicit)

--------------------
type float = System.Double

--------------------
type float<'Measure> = float
val totalScore: Async<float>
val sumByAsync: projection: ('T -> Async<'U>) -> source: AsyncSeq<'T> -> Async<'U> (requires member (+) and member Zero)
<summary> Asynchronously sum the mapped elements of an asynchronous sequence using an asynchronous projection. </summary>
val meanSquare: Async<float>
val averageBy: projection: ('T -> 'U) -> source: AsyncSeq<'T> -> Async<'U> (requires member (+) and member DivideByInt and member Zero)
<summary> Asynchronously compute the average of the mapped elements of an asynchronous sequence using a synchronous projection. Raises InvalidArgumentException if the sequence is empty. </summary>
val meanScore: Async<float>
val averageByAsync: projection: ('T -> Async<'U>) -> source: AsyncSeq<'T> -> Async<'U> (requires member (+) and member DivideByInt and member Zero)
<summary> Asynchronously compute the average of the mapped elements of an asynchronous sequence using an asynchronous projection. Raises InvalidArgumentException if the sequence is empty. </summary>
val digitParity: Async<(string * int) array>
type 'T array = 'T array
val countBy: projection: ('T -> 'Key) -> source: AsyncSeq<'T> -> Async<('Key * int) array> (requires equality)
<summary> Asynchronously count the elements of the input asynchronous sequence grouped by the result of the given key projection. Returns an array of (key, count) pairs. </summary>

Type something to start searching.