等待akka.net actor {}表达式中的F#异步任务

时间:2014-08-09 15:14:19

标签: f# akka.net

是否可以在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
}

2 个答案:

答案 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"