问题
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