是否可以在Async<'t>上等待(不阻止)在Akka.Net演员计算中?我希望实现与以下类似的东西。
actor {
let! msg = mailbox.Receive()
match msg with
| Foo ->
let! x = async.Return "testing 123" // Some async function, return just an example
() // Do something with result
}
答案 0 :(得分:4)
不,您无法在演员的邮箱中使用async
/ await
或其任何变体,并获得安全的结果。
每个参与者都维护自己的上下文,其中包括重要的细节,如上一条消息的发件人和可能发生变化的其他重要状态。 Actors以串行方式处理消息,因此一旦其邮箱内的呼叫完成,它立即开始处理其下一条消息 - 如果您在邮箱内放置await调用,则该actor将处理与您启动的邮件完全不同的消息。等待电话回来的时间。
利用异步调用和演员内部TAP的更好模式是使用PipeTo模式。看来我们在http://akkadotnet.github.io/还没有任何相关文档,所以我会给你一个真实的代码示例(在C#中):
public void Handle(ExplicitReplyOperation<CampaignsForAppRequest> message)
{
Context.IncrementMessagesReceived();
_loaderActor.Ask(message.Data).ContinueWith(r =>
{
var campaigns = (IList<Campaign>)r.Result;
message.Originator.Tell(new CampaignsForAppResponse()
{
AppId = message.Data.AppId,
ActiveCampaigns = campaigns
}, ActorRef.NoSender);
return campaigns;
}).PipeTo(Self);
}
在此示例中,我有TypedActor
继续执行任务,执行一些后处理,然后使用PipeTo
运算符(可以应用于任何{{1的Akka.NET扩展方法)一旦操作完成,就将任务的结果传递到这个actor的邮箱中。这样我可以关闭我需要的任何状态,并且我的actor可以继续以安全的方式处理消息,同时继续执行异步操作。
答案 1 :(得分:1)
这似乎有可能!
let system = ConfigurationFactory.Default() |> System.create "FSharpActors"
let asyncActor =
spawn system "MyActor"
<| fun mailbox ->
let rec loop() =
actor {
let! name = mailbox.Receive()
Akka.Dispatch.ActorTaskScheduler.RunTask(fun () ->
async {
printfn "Hello %s" name
do! Async.Sleep 5000
} |> Async.StartAsTask :> Threading.Tasks.Task)
return! loop()
}
loop()
asyncActor <! "Alice"
asyncActor <! "Bob"
asyncActor <! "Eve"