如何避免对Actor实例的可变引用
问题描述:
我正尝试在F#中获得一些Akka.NET参与者的一些经验。当一个演员需要将另一个演员作为自己的孩子时,我有这种情况。第一个演员会转换每条消息,然后将结果发送给其他演员。我使用actorOf2
函数来派生演员。这里是我的代码:如何避免对Actor实例的可变引用
let actor1 work1 work2 =
let mutable actor2Ref = null
let imp (mailbox : Actor<'a>) msg =
let result = work1 msg
if actor2Ref = null then
actor2Ref <- spawn mailbox.Context "decide-actor" (actorOf2 <| work2)
actor2Ref <! result
imp
let actor1Ref = actor1 work1' work2'
|> actorOf2
|> spawn system "my-actor"
我不喜欢的是可变的演员参考。但是我必须让它变得可变,因为我需要mailbox.Context
产生一个小孩演员,并且在第一次通话之前我没有任何背景。我看到this question,但我不知道如何将它应用于我的功能。
在更高级的场景中,我需要一个由键分区的子actor的集合。我在这种情况下使用了演员参考字典。有更好的(更多F#-ish)方法吗?
答
为了保持跨越迭代的“状态”,您需要明确地进行迭代。这样,你可以传递当前的“状态”作为尾调用参数。正如在这个问题您链接:
let actor1 work1 work2 (mailbox : Actor<'a>) =
let rec imp actor2 =
actor {
let! msg = mailbox.Receive()
let result = work1 msg
let actor2 =
match actor2 with
| Some a -> a // Already spawned on a previous iteration
| None -> spawn mailbox.Context "decide-actor" (actorOf2 <| work2)
actor2 <! result
return! imp (Some actor2)
}
imp None
而现在,你不需要使用actorOf2
或actorOf
产卵这个演员,因为它已经具有正确的签名:
let actor1Ref =
actor1 work1' work2'
|> spawn system "my-actor"
。
编辑
如果你担心多余的样板,没有什么能阻止你从包装样板远作为函数(毕竟,actorOf2
does something similar):
let actorOfWithState (f: Actor<'msg> -> 'state -> 'msg -> 'state) (initialState: 'state) mailbox =
let rec imp state =
actor {
let! msg = mailbox.Receive()
let newState = f mailbox state msg
return! imp newState
}
imp initialState
然后:
let actor1 work1 work2 (mailbox : Actor<'a>) actor2 msg =
let result = work1 msg
let actor2 =
match actor2 with
| Some a -> a
| None -> spawn mailbox.Context "decide-actor" (actorOf2 work2)
actor2 <! result
actor2
let actor1Ref =
actor1 work1' work2'
|> actorOfWithState
|> spawn system "my-actor"
答
你可以按照这些方法做一些事情,并且根本不存储对子actor的引用,因为Context已经为你做了这些。
let actor =
let ar = mailbox.Context.Child(actorName)
if ar.IsNobody() then
spawn mailbox.Context actorName handler
else ar
如果Context.Child查找证明是太慢,造就了memoized功能,保持可变性与其他隐藏代码将是非常容易做到的。
是的,我有这个选项,但恕我直言,这个模板与明确的接收和演员工作流程是比我的功能更多的样板。而且更难以进行单元测试。 – Mikhail
是的,更多的样板,但没有它,你不能保持状态。想一想:如果你的函数没有表示状态的任何参数,那么它所能做的就是依赖可变环境。 –
为了回应您的问题,我已更新了答案。 –