ET服务器框架学习笔记(十五)

ET服务器框架学习笔记(十五)

前言

前面好几篇都是关于通信协议的,本篇将对上篇说的Actor锁来个梳理,避免自己以后懵逼。

一、与Location锁相关组件

通过之前的文章的分析,可以得出与Location锁相关的类如下:

//协程锁组件
						Game.Scene.AddComponent<CoroutineLockComponent>();
						// location server需要的组件
						Game.Scene.AddComponent<LocationComponent>();
						
						// 访问location server的组件
						Game.Scene.AddComponent<LocationProxyComponent>();

二、CoroutineLockComponent

1.CoroutineLock

协程锁类,内部有一个Key,对应一个实体ID对应一个CoroutineLock锁,观点在于Dispose时,会调用CoroutineLockComponent.Instance.Notify(this.key);通知CoroutineLockComponent组件这个协程被释放掉是信息。

2.LockQueue

内部包含一个队列,类型为ETTaskCompletionSource,即一个异步tcs存入这个队列中,同时这个tcs关联一个协程CoroutineLock锁。

3.CoroutineLockComponent

包含一个单例,用于其他类直接调用。

  • Dictionary<long, LockQueue> lockQueues:一个字典类,一个实体ID,对应一个锁定的队列。
  • async ETTask Wait(long key)方法:1.从lockQueues中获取一个锁定队列;2.如果锁定队列不存在,那么说明没人操控这个实体,那么新建一个LockQueue与Key,并将其放入lockQueues中;3.如果存在说明之前已经有人在wait控制这个实体,那么创建一个TCS实例,返回tcs.Task,并将其存入到对应的队列中。
  • void Notify(long key):当有方法调用时,1.如果对应的LockQueue没有任何tcs了,直接释放掉lockQueue,2.如果还有tcs,那么从队列中取出一个tcs,然后设置他的SetResult,这样对应异步调用await方法的地方会被唤醒继续执行。

三、LocationComponent

1.LockInfo

锁定信息类,内部包含一个锁定的实体的LockInstanceId,一个CoroutineLock锁。

2.LocationComponent

  • locations:字典类,定位信息,一个实体的ID,对应一个实体的InstanceId

  • lockInfos:字典类,一个实体的ID,对应一个LockInfo信息。

  • async ETTask Add(long key, long instanceId):先异步调用CoroutineLockComponent.Instance.Wait,这样当被其他锁定的时候,会暂停到这里。

  • async ETTask Remove(long key):从locations中移除定位信息。

  • async ETTask Get(long key):从locations中拿到一个实体ID对应的最新的InstanceId。

  • async ETVoid Lock(long key, long instanceId, int time = 0):锁定函数,这个函数很关键。
    1.从CoroutineLockComponent.Instance.Wait获取一个CoroutineLock。
    2.通过instanceId与coroutineLock,实例化一个LockInfo,然后放入lockInfos中。
    3.如果time>0,则增加一个定时器,到时自动解锁。

  • void UnLock(long key, long oldInstanceId, long newInstanceId):解锁,
    1.新的InstanceId,将locations中的InstanceId更新为新的newInstanceId。
    2.从lockInfos中获取到lockInfo,调用lockInfo的Dispose
    3.从而调用CoroutineLock的Dispose,调用CoroutineLockComponent.Instance.Notify
    4.从对应的lockQueue中以先进先出的方式,拿到一个tcs,并调用SetResult设置结果。从而使得再最先调用await的异步代码处进行唤醒,继续执行。

四、LocationProxyComponent

这个组件一般是出了Location服务外的内网服务会挂载,内部封装了对定位服务的增加,删除,锁定,解锁等操作。实际就是给Location服务发送协议。
1.Awake:主要任务就是初始化Location服务地址
2.Add:发送一条ObjectAddRequest到Location服务
3.Lock:发送一条ObjectLockRequest到Location服务
4.UnLock:发送一条ObjectUnLockRequest到Location服务
5.Remove:发送一条ObjectRemoveRequest到Location服务
6.Get:发送一条ObjectGetRequest到Location服务。

上面分别对应了下面的实例处理方法:
ObjectAddRequestHandler,
ObjectLockRequestHandler,
ObjectUnLockRequestHandler,
ObjectRemoveRequestHandler,
ObjectGetRequestHandler

对应是调用LocationComponent的各个方法。

注意:
ET在很多地方都调用了类型下面的代码:

using (await CoroutineLockComponent.Instance.Wait(key + (int)AppType.Location)){}

这里的using,有个特别之处,在于当结束{}时,会自动调用()内部类的Dispose方法。因此当没有锁定时,wait函数返回一个 return ComponentFactory.Create<CoroutineLock, long>(key);,一个CoroutineLock实例。然后结束using时会自动调用CoroutineLock的DisPose方法,从而调用到CoroutineLockComponent.Instance.Notify(this.key);从而将锁给移除了。

还需要注意到LocationComponent的Lock方法,并没有使用using而是:CoroutineLock coroutineLock = await CoroutineLockComponent.Instance.Wait(key + (int)AppType.Location);
这样的话,对于多个锁定,都会进入到锁定队列中。而对于其他用法,重复调用时,由于using语法,结束一个,立马就会销毁一个,等于是只会有一个锁定,等待真正的UnLock来触发。

同样的道理适用于在InnerMessageDispatcher时,也会使用await CoroutineLockComponent.Instance.Wait(message.ActorId)的方式。所以在后续使用中,需要用到Location服务的时候,都应该用这种方式。
大致的原因在ETBOOK中有说,有需要可以去看。

总结

到这里总算应该将所有ET通信的内容,都简单梳理了一遍。对Actor模型,以及分布式框架的理解也多了一分,再次感谢ET作者开源,并且使用相对轻量一些的C#来实现。
希望后面的ET6.0能带来更多惊喜,下一篇开始,对ET中其他的业务模块进行单独分析,一个个来吧。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值