2015-03-17 6 views
9

In C# ReceiveActor s kann ich nur State als private Felder in der Klasse haben. Wie soll ich das idiomatisch mit der F # API machen?Wie speichert man den Status in einem F # Akka.NET Actor?

Ist das eine gute Idee? Irgendwelche Alternativen?

let handleMessage (mailbox: Actor<'a>) msg = 
    let mutable i = 1 
    match msg with 
    | Some x -> i <- i + x 
    | None ->() 
+0

Nicht das, was du bist suchen, aber für [F # -Agenten ist der idiomatische Ansatz, eine rekursive Schleife zu verwenden, um den Zustand zu tragen] (https://msdn.microsoft.com/en-us/library/ee370357.aspx). Wenn Sie jedoch mit Akka.NET den Mutations-orientierten Pfad herunterfahren, kann es sich als unmöglich erweisen, es "schön" zu machen. Können Sie einen Akteur für Akka.NET auf andere Weise implementieren als von ReceiveActor? Etwas, mit dem Sie eine rekursive Poll-Schleife verwenden könnten? –

+1

BTW, wenn es eine andere idiomatische Lösung gibt, ich bin nur ignorant darüber und würde gerne auch erzogen werden :) –

Antwort

18

Die Art und Weise, wie Sie vorgeschlagen haben, ist völlig angemessen, um den Zustand innerhalb des Akteurs zu speichern. Die Nebenläufigkeitsbeschränkungen, nur eine Nachricht zu jeder Zeit zu verarbeiten, bedeutet, dass es nicht möglich ist, in einen ungültigen Zustand zu gelangen, als Folge einer Konkurrenz auf einem gemeinsam genutzten Speicherplatz.

Allerdings ist es nicht die idiomatische Option. Akka.Net bietet eine F # API für die Arbeit mit Schauspielern ähnlich wie F # MailboxProcessors. In diesem Fall definieren Sie Ihren Akteur als eine tail rekursive Funktion, die sich selbst mit einem neuen Status aufruft. Hier ist ein Beispiel

spawn system "hello" <| 
    fun mailbox -> 
     let rec loop state = 
      actor { 
       let! msg = mailbox.Receive() 
       printfn "Received %A. Now received %s messages" msg state 
       return! loop (state + 1) //Increment a counter for the number of times the actor has received a message 
      } 
     loop 0 

Für eine vollständige Dokumentation über die Akka.Net F # API http://getakka.net/wiki/FSharp%20API

7

Es gibt zwei Lösungen, die beide verwenden explizite rekursive Schleife Definition, Hauptkonzept von Akka F # Schauspieler sehen.

Zuerst Sie Variablen definieren, die nur innerhalb Schauspieler Umfang, bevor Schleife Definition (in Beispiel I unten geändert haben i Definition Referenzzelle, weil veränderbare Variablen nicht durch Schließungen erfasst werden können) sichtbar sein soll:

let actorRef = 
    spawn system "my-actor" <| fun mailbox -> 
     let i = ref 1 
     let rec loop() = 
      actor { 
       let! msg = mailbox.Receive() 
       match msg with 
       | Some x -> i := !i + x 
       | None ->() 
       return! loop() 
      } 
     loop() 

jedoch mehr empfohlene Lösung ist Ihren Zustand unveränderlich während der Nachrichtenbehandlung zu halten, und es nur dann ändern, wenn in der nächsten Schleife Anrufen, so wie dies vorbei:

let actorRef = 
    spawn system "my-actor" <| fun mailbox -> 
     let rec loop i = 
      actor { 
       let! msg = mailbox.Receive() 
       match msg with 
       | Some x -> return! loop (i + x) 
       | None -> return! loop i 
      } 
     loop 1 // invoke first call with initial state