2015-03-17 16 views
9

W C# ReceiveActor s Mogę po prostu mieć stan jako prywatne pola w klasie. Jak mam to zrobić w sposób idiomatyczny za pomocą F # API?Jak zapisać stan w F # Akka.NET Actor?

Czy to dobry pomysł? Jakieś alternatywy?

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

Nie to, co masz szukając, ale dla [agentów F, podejście idiomatyczne polega na użyciu pętli rekursywnej do przenoszenia stanu] (https://msdn.microsoft.com/en-us/library/ee370357.aspx). Jeśli jednak Akka.NET zmusi cię do ścieżki zorientowanej na mutacje, może się okazać, że nie da się tego zrobić "ładnie". Czy możesz wdrożyć aktora dla Akka.NET w inny sposób niż wynikający z 'ReceiveActor'? Coś, co umożliwi ci korzystanie z pętli rekurencyjnej? –

+1

BTW, jeśli istnieje inne rozwiązanie idiomatyczne, jestem po prostu nieświadomy tego i chciałbym też być wykształcony :) –

Odpowiedz

18

Sposób, w jaki zaproponowałeś, jest całkowicie odpowiedni jako sposób na zachowanie stanu w aktoru. Ograniczenia współbieżności tylko wiadomości przetwarzania 1 w dowolnym momencie oznacza, że ​​nie można uzyskać nieprawidłowych stanów w wyniku rywalizacji w lokalizacji pamięci współużytkowanej.

Jednak nie jest to opcja najbardziej idiomatyczna. Akka.Net udostępnia interfejs API F # do pracy z aktorami w podobny sposób jak F # MailboxProcessors. W tym przypadku definiujesz swojego aktora jako funkcję rekurencyjną ogona, która wywołuje się z pewnym nowym stanem. Oto przykład

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 

Dla pełnej dokumentacji na Akka.Net F # API zobaczyć http://getakka.net/wiki/FSharp%20API

7

Istnieją dwa rozwiązania, oba z nich korzystać wyraźny rekurencyjnej definicji pętli, główną koncepcję Akka F # aktorów.

Najpierw można zdefiniować zmienne, które powinny być widoczne tylko wewnątrz zakresu aktora, przed definicji pętli (w przykładzie poniżej Zmieniłem i definicję odwołanie do komórki, ponieważ zmienne Zmienne nie mogą być przechwytywane przez zamknięć):

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

jednak bardziej poinformowani rozwiązaniem jest, aby utrzymać swój stan niezmienny podczas obsługi wiadomości i zmienić go tylko podczas przechodzenia w następnych połączeń pętli, podobnie jak to:

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