Warranty Procedure for Messages Sent to a Mailbox Processor

I have a mailbox processor that receives a fixed number of messages:

let consumeThreeMessages = MailboxProcessor.Start(fun inbox -> async { let! msg1 = inbox.Receive() printfn "msg1: %s" msg1 let! msg2 = inbox.Receive() printfn "msg2: %s" msg2 let! msg3 = inbox.Receive() printfn "msg3: %s" msg3 } ) consumeThreeMessages.Post("First message") consumeThreeMessages.Post("Second message") consumeThreeMessages.Post("Third message") 

These messages must be processed exactly in the sending order. During my testing, it prints exactly what it should:

 First message Second message Third message 

However, since posting messages is asynchronous, it seems that message 3 messages can quickly lead to the processing of elements in any order. For example, I do not want to receive messages out of order and receive something like this:

 Second message // <-- oh noes! First message Third message 

Are messages available that will be received and processed in the sent order? Or is it possible that messages will be received or processed out of order?

+7
concurrency f #
source share
1 answer

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() // Start the task twice doTaskAsync() doTaskAsync() 

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.

+8
source share

All Articles