The code in your consumeThreeMessages function consumeThreeMessages always execute in order, due to how a # x workflows work.
The following code:
async { let! msg1 = inbox.Receive() printfn "msg1: %s" msg1 let! msg2 = inbox.Receive() printfn "msg2: %s" msg2 }
Roughly translates into:
async.Bind( inbox.Receive(), (fun msg1 -> printfn "msg1: %s" msg1 async.Bind( inbox.Receive(), (fun msg2 -> printfn "msg2: %s" msg2) ) ) )
When you look at the formatted form, it is clear that the code is executed in sequential order. The “async” part comes into play in the async.Bind implementation, which will start the calculation asynchronously and “wake up” when it completes to complete the execution. Thus, you can take advantage of asynchronous hardware operations, rather than wasting time on OS threads waiting for I / O.
This does not mean that you cannot run concurrency problems when using F # async workflows. Imagine you did the following:
let total = ref 0 let doTaskAsync() = async { for i = 0 to 1000 do incr total } |> Async.Start()
The code above will have two asynchronous workflows that simultaneously change the same state.
So, to briefly answer your question: inside the body of one asynchronous block, everything will be executed in order. (That is, the next line after let! Or do! Does not execute until the async operation completes.) However, if you split the state between two async tasks, then all bets are disabled. In this case, you will need to consider locking or using parallel data structures that come with CLR 4.0.
Chris smith
source share