2010-02-08 6 views
7

Ich habe einen Mailbox-Prozessor, der eine feste Anzahl von Nachrichten empfängt:Garantie Reihenfolge der Nachrichten auf die Mailbox-Prozessor geschrieben

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") 

Diese Nachrichten in genau der Reihenfolge gesendet behandelt werden sollte. Während meiner Tests, druckt er genau, was es sein sollte:

First message 
Second message 
Third message 

Da jedoch Nachricht Posting asynchron ist, klingt es wie Posting-3-Nachrichten schnell führen könnten in Einzelteile in beliebiger Reihenfolge verarbeitet werden. Zum Beispiel Ich will nicht Nachrichten aus, um erhalten und so etwas wie dieses:

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

garantiert Nachrichten in der Reihenfolge gesendet, empfangen und verarbeitet werden? Oder ist es möglich, dass Nachrichten außerhalb der Reihenfolge empfangen oder verarbeitet werden?

+0

Das ist eine wirklich gute Frage. Ich habe FSharp.Core.dll untersucht, aber der Code ist als C# schwer zu verstehen. – ChaosPandion

Antwort

8

Der Code in Ihrer consumeThreeMessages-Funktion wird immer in der Reihenfolge ausgeführt, weil die Async-Workflows von F # funktionieren.

Der folgende Code:

async { 
      let! msg1 = inbox.Receive() 
      printfn "msg1: %s" msg1 

      let! msg2 = inbox.Receive() 
      printfn "msg2: %s" msg2 

     } 

übersetzt in etwa:

async.Bind(
    inbox.Receive(), 
    (fun msg1 -> 
     printfn "msg1: %s" msg1 
     async.Bind(
      inbox.Receive(), 
      (fun msg2 -> printfn "msg2: %s" msg2) 
     ) 
    ) 
) 

Wenn Sie an der entzuckert Form aussehen, ist es klar, dass der Code in seriell ausführt. Der 'asynchrone' Teil kommt in der Implementierung von async.Bind zum Einsatz, der die Berechnung asynchron startet und 'aufwacht', wenn die Ausführung beendet ist. Auf diese Weise können Sie asynchrone Hardwarefunktionen nutzen und keine Zeit für OS-Threads verschwenden, die auf IO-Vorgänge warten.

Das bedeutet nicht, dass Sie bei der Verwendung der asynchronen F # -Arbeitsabläufe keine Gleichzeitigkeitsprobleme bekommen können. Stellen Sie sich folgendes vor:

let total = ref 0 

let doTaskAsync() = 
    async { 
     for i = 0 to 1000 do 
      incr total 
    } |> Async.Start() 

// Start the task twice 
doTaskAsync() 
doTaskAsync() 

Der obige Code wird zwei asynchrone Workflows haben, die denselben Zustand zur gleichen Zeit ändern.

Also, um Ihre Frage in Kürze zu beantworten: innerhalb des Körpers eines einzelnen asynchronen Blocks werden die Dinge immer in der Reihenfolge ausgeführt. (Das heißt, die nächste Zeile nach einem let! Oder do! Wird erst ausgeführt, wenn die asynchrone Operation abgeschlossen ist.) Wenn Sie jedoch den Status zwischen zwei asynchronen Tasks teilen, sind alle Wetten deaktiviert. In diesem Fall müssen Sie das Sperren oder Verwenden von Concurrent Data Structures in Betracht ziehen, die mit CLR 4.0 geliefert werden.

+0

+1, + Antwort: macht Sinn :) Wissen Sie, ich war anfangs nicht 100% sicher, weil ich, nur als Experiment, Mailbox-Prozessoren in C# implementieren wollte, und ich immer unerwünschte Ergebnisse mit sequentiellen Aufrufen an meine bekam GetMsg (Aktion >) Implementierung. Meine verschachtelten Aufrufe von 'GetMsg (x => GetMsg (y => GetMsg (z => ...>)))' funktionieren gut, aber sequentielle Aufrufe 'inbox.GetMsg (x => ...); inbox.GetMsg (x =>); inbox.GetMsg (x => ...) 'wird außerhalb der Reihenfolge verarbeitet. Statt "es ist wahrscheinlich etwas mit meinem Code nicht in Ordnung", mein erster Gedanke war "Hey, ich frage mich, ob F # gebrochen ist?" Zum Glück nein;) – Juliet

+0

Ich bin froh, dass wir F # Gurus auf SO haben. Wohin würden wir uns sonst wenden? – ChaosPandion

+0

Kann aber die Post nachbestellt werden? –

Verwandte Themen