acotor模型理解3-actor消息的发送器ActorMessageSender

开始的地方:网关服务器

OuterMessageDispatcher,判断是iActorMessage消息,这里处理actor消息。

case IActorMessage iActorMessage: // gate session收到actor消息直接转发给actor自己去处理
                {
                    long unitId = session.GetComponent<SessionPlayerComponent>().Player.UnitId;//获取unit在map服务器的unitid
                    ActorMessageSender actorMessageSender = Game.Scene.GetComponent<ActorMessageSenderComponent>().Get(unitId);//用unit在map服务器的unitid来创建ActorMessageSender ,这个ActorMessageSender内会根据unitid获取map服务器的session,并向map服务器的session发送actor消息
                    actorMessageSender.Send(iActorMessage);//开始向map服务器的session发送actor消息
                    return;
                }

主题来了,actor消息的发送器的处理流程

ActorMessageSender
 

1,自身不断执行UpdateAsync,处理流程

1.1UpdateAsync:

public static async void UpdateAsync(this ActorMessageSender self)
        {
            try
            {
                while (true)
                {
                    ActorTask actorTask = await self.GetAsync();//会在这等待GetAsync返回值
                    if (self.IsDisposed)
                    {
                        return;
                    }

                    if (actorTask.ActorMessage == null)
                    {
                        return;
                    }

                    await self.RunTask(actorTask);//创建线程,执行RunTask函数,继续下一个循环
                }
            }
            catch (Exception e)
            {
                Log.Error(e);
            }
        }

1.2GetAsync:

private static Task<ActorTask> GetAsync(this ActorMessageSender self)
        {
            if (self.WaitingTasks.Count > 0)//刚开始没有发过来消息时,等待任务数量是0
            {
                ActorTask task = self.WaitingTasks.Peek();
                return Task.FromResult(task);
            }

            self.Tcs = new TaskCompletionSource<ActorTask>();//等待任务数量是0时,会执行这里,创建一个TaskCompletionSource,作用是,可以在其他地方调用SetResult方法,给task赋值
            return self.Tcs.Task;//这里将self.Tcs里的task返回,但是没有调用SetResult方法,所以在这里会等待,激活条件是2.3AllowGet中, t.SetResult(task);这句话
        }

1.3RunTask:

private static async Task RunTask(this ActorMessageSender self, ActorTask task)
        {
            Session session = Game.Scene.GetComponent<NetInnerComponent>().Get(self.Address);

            task.ActorMessage.ActorId = self.ActorId;
            IResponse response = await session.Call(task.ActorMessage);
            

            // 发送成功
            switch (response.Error)
            {
                case ErrorCode.ERR_NotFoundActor:
                    // 如果没找到Actor,重试
                    ++self.FailTimes;

                    // 失败MaxFailTimes次则清空actor发送队列,返回失败
                    if (self.FailTimes > self.MaxFailTimes)
                    {
                        // 失败直接删除actorproxy
                        Log.Info($"actor send message fail, actorid: {self.Id}");
                        self.Error = response.Error;
                        self.GetParent<ActorMessageSenderComponent>().Remove(self.Id);
                        return;
                    }

                    // 等待1s再发送
                    await Game.Scene.GetComponent<TimerComponent>().WaitAsync(1000);
                    self.ActorId = await Game.Scene.GetComponent<LocationProxyComponent>().Get(self.Id);
                    self.Address = Game.Scene.GetComponent<StartConfigComponent>()
                            .Get(IdGenerater.GetAppIdFromId(self.ActorId))
                            .GetComponent<InnerConfig>().IPEndPoint;
                    self.AllowGet();
                    return;
                
                case ErrorCode.ERR_ActorNoMailBoxComponent:
                    self.Error = response.Error;
                    self.GetParent<ActorMessageSenderComponent>().Remove(self.Id);
                    return;
                
                default:
                    self.LastSendTime = TimeHelper.Now();
                    self.FailTimes = 0;

                    self.WaitingTasks.Dequeue();
                    
                    task.Tcs?.SetResult(response);//task.Tcs激活返回值处,使调用return task.Tcs.Task;这里继续执行。2send并没有用到,3call用到了
                    
                    return;
            }
        }

2,外面主动调用Send函数,处理流程

2.1Send:

public static void Send(this ActorMessageSender self, IActorMessage message)
        {
            ActorTask task = new ActorTask(message);//构造一个ActorTask
            self.Add(task);//将ActorTask 添加到等待队列
        }

2.2Add:

private static void Add(this ActorMessageSender self, ActorTask task)
        {
            if (self.IsDisposed)
            {
                throw new Exception("ActorProxy Disposed! dont hold actorproxy");
            }

            self.WaitingTasks.Enqueue(task);//添加进等待队列
            // failtimes > 0表示正在重试,这时候不能加到正在发送队列,默认是等于0的。
            if (self.FailTimes == 0)
            {
                self.AllowGet();//从等待队列里取任务,当然会在里面做判断,什么情况下可以取
            }
        }

2.3AllowGet:

private static void AllowGet(this ActorMessageSender self)
        {
            if (self.Tcs == null || self.WaitingTasks.Count <= 0)//self.Tcs是空,等待队列是空,都会返回,不做任何处理。在这里,

也就是说,如果队列里有等待任务,是不允许下面取出任务的;并且self.Tcs 这个任务没有创建,也不允许下面取出任务的,也就是说明,这个actor消息的发送器正在处理消息中
            {
                return;
            }

            ActorTask task = self.WaitingTasks.Peek();//从等待队列取出任务,

            var t = self.Tcs;//将任务给本函数
            self.Tcs = null;//将自身的任务置空
            t.SetResult(task);//上面的 1.2GetAsync方法中 ,停在这里return self.Tcs.Task;,使这里激活,继续执行下去
        }

3外面主动调用Call函数,处理流程

3.1Call:流程和send类似,只有 多了一个返回值,return task.Tcs.Task;

public static Task<IResponse> Call(this ActorMessageSender self, IActorRequest request)
        {
            TaskCompletionSource<IResponse> tcs = new TaskCompletionSource<IResponse>();//创建一个TaskCompletionSource,用来返回task
            ActorTask task = new ActorTask(request, tcs);//创建任务
            self.Add(task);//添加任务
            return task.Tcs.Task;//返回task结果,在这里会阻塞,直到1.3RunTask中 task.Tcs?.SetResult(response)执行后,才会激活,继续执行
        }

3.2Add:

同上

3.3AllowGet:

同上

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值