【问题标题】:Awaiting an F# async task inside an akka.net actor{} expression在 akka.net actor{} 表达式中等待 F# 异步任务
【发布时间】:2014-10-02 21:43:44
【问题描述】:

是否可以在 Akka.Net Actor 计算中的 Async 上等待(不阻塞)?我想实现类似于以下的目标。

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
}

【问题讨论】:

  • 基于此:github.com/akkadotnet/akka.net/blob/… 如果 Akka.net 选择在那里重新配置他们自己的 AsyncBuilder 似乎很合适......所以不,你不能在那里使用 F# 的 Asyncs 助手(F# 中没有 Monad-Transformers ) - 当然,您可以尝试将您需要的内容重新添加到 Akka 的 Cont 中(使用 Async.StartWithContinuations)

标签: f# akka.net


【解决方案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"

【讨论】:

    【解决方案2】:

    不,您不能在演员的邮箱中使用 async / await 或其任何变体并获得安全的结果。

    每个参与者都维护自己的上下文,其中包括重要的细节,如前一条消息的发送者和其他可能改变的重要状态。 Actor 串行处理消息,因此一旦其邮箱中的调用完成,它就会立即开始处理下一条消息 - 如果您在邮箱中放置 await 调用,则 Actor 将处理与您开始处理的消息完全不同的消息您的等待电话返回的时间。

    利用异步调用和 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 运算符(可以应用于任何Task 对象的Akka.NET 扩展方法)来管道操作完成后,任务结果将发送到此参与者的邮箱。这样我就可以关闭我需要的任何状态,并且我的 Actor 可以在此异步操作继续时以安全的方式继续处理消息。

    【讨论】:

    • 谢谢。这可行,但并不理想,因为它使代码更难阅读。
    • @Oenotria 在 Akka.NET 跟踪器 github.com/akkadotnet/akka.net/issues/44 中有一个问题,但是这个问题很难解决,邮箱和组成异步等待代码的状态机需要交互(不知何故)
    • 使用自定义actor{}计算表达式背后的原因是什么?为什么不像标准 F# MailboxProcessor 那样使用 async{}?
    • 它构建了一个可以远程部署的表达式,即actor builder中的actor代码可以推送到远程节点,就像erlang..普通的async builder做不到。跨度>
    猜你喜欢
    • 1970-01-01
    • 2014-09-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-03-18
    • 2015-05-22
    • 2016-07-24
    • 2013-02-10
    相关资源
    最近更新 更多