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?
Use Promise. all for the parallel function calls, the answer behaviors not correctly when the error occurs. Caveat: It doesn't matter if the await calls are on the same line or on different lines, so long as the first await call happens after all of the asynchronous calls.
There is no parallelism here, as the “async Task” does not automatically make something run in in parallel. This will spawn 2 threads, run them simultaneously, and return when both threads are done. This will create a list of Tasks to be run at the same time.
In order to run multiple async/await calls in parallel, all we need to do is add the calls to an array, and then pass that array as an argument to Promise. all() . Promise. all() will wait for all the provided async calls to be resolved before it carries on(see Conclusion for caveat).
so an asynchronous programming implemented using async and await in c# 4.5 can also be considered parallel programming? I would say yes.
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With