Mark Vincze
Mark Vincze

Reputation: 8033

How to execute two Async<> calls with different result types in parallel?

I have two asynchronous operations, so I have these functions:

// Returs Async<Person>
let GetPerson =
  ...

// Returs Async<Address>
let GetAddress =
  ...

What is the idiomatic way to execute them in parallel and get their results?

My starting point is this approach.

let MyFunc = async {
    let! person = GetPerson()
    let! address = GetAddress()
    ...
  }

This works, but this runs the two operations sequentially.

I also tried this (sort of based on my C# experience).

let MyFunc = async {
    let personA = GetPerson()
    let addressA = GetAddress()
    let! person = personA
    let! address = addressA
    ...
  }

But it doesn't work, it also runs the two operations sequentially.

What most of the documentation says is to use Async.Parallel with a sequence, but the problem is that the result type of the two operations are different, so I cannot put them in a sequence.

let MyFunc = async {
    let personA = GetPerson()
    let addressA = GetAddress()

    [personA; addressA]
    |> Async.Parallel
    ...
  }

This gives a compilation error, because the two values have different types. (And also, with this syntax, how could I get the actual results?)

What is the idiomatic way to do this?

Upvotes: 8

Views: 232

Answers (1)

Tomas Petricek
Tomas Petricek

Reputation: 243041

The idiomatic approach is to start both computations using Async.StartAsChild and then wait for their completion using a second let!:

let MyFunc = async {
    let! personWork = GetPerson() |> Async.StartChild
    let! addressWork = GetAddress() |> Async.StartChild
    let! person = personWork
    let! address = addressWork
    // (...)
  }

Just calling GetPerson does not actually start the work - unlike in C# where tasks are created started, F# workflows are just descriptions of the work to be done, so they need to be started explicitly. The Async.StartChild operation gives you a workflow that starts the work and returns another workflow that can be used for wait for its completion.

Upvotes: 10

Related Questions