Awaiting an F# async task inside an akka.net actor{} expression

这一生的挚爱 提交于 2019-12-06 03:44:27

问题


Is it possible to wait (without blocking) on an Async<'t> within an Akka.Net actor computation? I want to achieve something similar to the following.

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
}

回答1:


No you can't use async / await or any variant thereof inside an actor's mailbox and get safe results.

Each actor maintains its own context, which includes important details like the Sender of the previous message and other important pieces of state which might change. Actors process messages serially, so as soon as the call inside its mailbox finishes it immediately begins processing its next message - if you put an await call inside the mailbox, the actor will be processing a totally different message than the one you started with by the time your await call returns.

A better pattern for leveraging asynchronous calls and the TAP inside actors is to use the PipeTo pattern. It looks like we don't have any documentation for this yet at http://akkadotnet.github.io/, so I'll give you a real-world code sample (in 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);
    }

In this sample I have a TypedActor that continues a Task, does some post-processing, and then uses the PipeTo operator (an Akka.NET extension method you can apply to any Task object) to pipe the results of the task into this actor's mailbox once the operation is finished. That way I can close over any of the state I need and my actor can continue processing messages in a safe way while this async operation continues.




回答2:


This now seems to be possible!

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"


来源:https://stackoverflow.com/questions/25219964/awaiting-an-f-async-task-inside-an-akka-net-actor-expression

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!