I am trying to learn how async
and let!
work in F#.
All the docs i've read seem confusing.
What's the point of running an async block with Async.RunSynchronously? Is this async or sync? Looks like a contradiction.
The documentation says that Async.StartImmediate runs in the current thread. If it runs in the same thread, it doesn't look very asynchronous to me... Or maybe asyncs are more like coroutines rather than threads. If so, when do they yield back an forth?
Quoting MS docs:
The line of code that uses let! starts the computation, and then the thread is suspended until the result is available, at which point execution continues.
If the thread waits for the result, why should i use it? Looks like plain old function call.
And what does Async.Parallel do? It receives a sequence of Async<'T>. Why not a sequence of plain functions to be executed in parallel?
I think i'm missing something very basic here. I guess after i understand that, all the documentation and samples will start making sense.
Many good answers here but I thought I take a different angle to the question: How does F#'s async really work?
Unlike
async/await
in C# F# developers can actually implement their own version ofAsync
. This can be a great way to learn howAsync
works.(For the interested the source code to
Async
can be found here: https://github.com/Microsoft/visualfsharp/blob/fsharp4/src/fsharp/FSharp.Core/control.fs)As our fundamental building block for our DIY workflows we define:
This is a function that accepts another function (called the continuation) that is called when the result of type
'T
is ready. This allowsDIY<'T>
to start a background task without blocking the calling thread. When the result is ready the continuation is called allowing the computation to continue.The F#
Async
building block is a bit more complicated as it also includes cancellation and exception continuations but essentially this is it.In order to support the F# workflow syntax we need to define a computation expression (https://msdn.microsoft.com/en-us/library/dd233182.aspx). While this is a rather advanced F# feature it's also one of the most amazing features of F#. The two most important operations to define are
return
&bind
which are used by F# to combine ourDIY<_>
building blocks into aggregatedDIY<_>
building blocks.adaptTask
is used to adapt aTask<'T>
into aDIY<'T>
.startChild
allows starting several simulatenousDIY<'T>
, note that it doesn't start new threads in order to do so but reuses the calling thread.Without any further ado here's the sample program:
The output of the program should be something like this:
When running the program note that
Waiting for key
is printed immidiately as the Console thread is not blocked from starting workflow. After about 700ms the result is printed.I hope this was interesting to some F# devs