Iai*_*ain 10 f# actor akka.net
在C#中,ReceiveActor我可以在类中将状态作为私有字段.我应该如何使用F#API以惯用的方式执行此操作?
这是一个好主意吗?任何替代品?
let handleMessage (mailbox: Actor<'a>) msg =
let mutable i = 1
match msg with
| Some x -> i <- i + x
| None -> ()
Run Code Online (Sandbox Code Playgroud)
bru*_*own 18
你提出的方式完全适合作为在演员中存储状态的手段.任何时候只处理1条消息的并发约束意味着由于共享内存位置的争用而无法进入无效状态.
但是,这不是最惯用的选择.Akka.Net提供了一个F#API,以与F#MailboxProcessors类似的方式与actor一起工作.在这种情况下,您将actor定义为尾递归函数,该函数使用一些新状态调用自身.这是一个例子
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
Run Code Online (Sandbox Code Playgroud)
有关Akka.Net F#API的完整文档,请参阅http://getakka.net/wiki/FSharp%20API
有两种解决方案,它们都使用显式递归循环定义,Akka F#actors的主要概念.
首先,您可以在循环定义之前定义变量(仅在actor的作用域内可见)(在下面的示例中,我已将i定义更改为引用单元格,因为闭包不能捕获可变变量):
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()
Run Code Online (Sandbox Code Playgroud)
但是,更多建议的解决方案是在消息处理期间保持状态不可变,并且仅在传入下一个循环调用时更改它,如下所示:
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
Run Code Online (Sandbox Code Playgroud)