处理未包含在 become 中的 received

Handling a received not covered in become

我正在使用 Akka.NET 开发物流模拟。

尝试过各种模式后,在我看来,使用 become 的 FSM 类型行为将大大简化开发。

系统有一个重复的时钟滴答消息,所有相关参与者都会收到该消息,以便模拟整个模拟系统的加速时间流逝。此时钟滴答消息应由订阅它的所有参与者处理,无论哪个消息循环当前对任何特定参与者处于活动状态。

我是否认为在所有消息循环中处理时钟消息的唯一方法是在所有消息循环中显式检查它,或者是否有一种方法可以定义无论哪个消息循环都处理的消息活跃吗?

如果是前者,我的想法是检查 ReceiveAny 中的时钟滴答消息,无论如何所有消息循环都需要它,然后传递它到合适的处理程序。

您可以在模拟时使用隐藏来隐藏消息。我想出了以下代码示例来更好地解释它是如何工作的:

// See https://aka.ms/new-console-template for more information
using Akka.Actor;
using Akka.NET_Whosebug_Questions_tryout.Questions;


var actorSystem = ActorSystem.Create("Whosebug");
var sim = actorSystem.ActorOf(Props.Create(()=> new Whosebug71079733()));
sim.Tell(5000L);
sim.Tell("string");
sim.Tell(1000L);
sim.Tell("strin2");
sim.Tell("strin3");
Console.ReadLine();

public class Whosebug71079733 : ReceiveActor, IWithUnboundedStash
    {
        public IStash Stash { get ; set ; }
        private readonly IActorRef _simActor;
        public Whosebug71079733()
        {
            _simActor = Context.ActorOf<SimulationActor>();
            ClockTickMessage();
        }
        private void Simulate(long ticks)
        {
            Console.WriteLine($"Ticks: {ticks}");

            Receive<Done>(d => 
            {
                Console.WriteLine("Simulation done");
                Become(ClockTickMessage);   
                Stash?.Unstash();    
            });

            // you can add additional messages that may to be handled while the simulation is happening
            // e.g: 
            Receive<string>(s => Console.WriteLine($"received in '{s}' in simulation"));

            //While the simulation is on-going, add the incoming message into a queue/stash it
            // so that it is not lost and can be picked and handled after stimulation is done
            ReceiveAny(any =>
            {
                Stash.Stash();
                Console.WriteLine($"Stashed Ticks: {any}");
            });
            _simActor.Tell(ticks);
        }
        private void ClockTickMessage()
        {
            // you can create an object to represent the ClockTickMessage
            Receive<long>(ticks => 
            {
                Become(() => Simulate(ticks));
            });
        }
    }
    /// <summary>
    /// We need to run simulation in a another actor so that the parent actor can keep receiving ClockTicksMessages
    /// In case the sim takes a long time to become
    /// </summary>
    public sealed class SimulationActor : ReceiveActor
    {
        private IActorRef _sender;
        public SimulationActor()
        {
            Receive<long>(l =>
            {
                _sender = Sender;
                Thread.Sleep(TimeSpan.FromMilliseconds(l));
                _sender.Tell(Done.Instance);    
            });
        }
    }
    public sealed class Done
    {
        public static Done Instance = new Done();
    }