ET|07 ET框架技术点研究
协程锁
协程锁机制 - ET社区 (et-framework.cn)
举个客户端的例子,资源加载ab包,ab包假如使用异步加载,那可能出现一个协程正在加载ab包,还没加载完,另外协程又开始加载这个ab包,那就出问题了。我们显然希望第二个协程要等待第一个协程加载完成,再往下执行,这样可以判断这个包加载过了就不需要再加载了。
核心API
CoroutineLockComponent.Instance.Wait(CoroutineLockType,Key,OuterTime);
-
CoroutineLockType 协程锁类型,是一个Enum
public static class CoroutineLockType { public const int None = 0; public const int Location = 1; // location进程上使用 public const int ActorLocationSender = 2; // ActorLocationSender中队列消息 public const int Mailbox = 3; // Mailbox中队列 public const int UnitId = 4; // Map服务器上线下线时使用 public const int DB = 5; public const int Resources = 6; public const int ResourcesLoader = 7; public const int LoadUIBaseWindows = 8; public const int Max = 100; // 这个必须最大 }
- Key 加锁的唯一Key,Int
- OuterTime 失效时间,超过这个时间默认解锁,Int,默认60000(毫秒)
核心调用如下:
public static async ETTask<CoroutineLock> Wait(...)
{
// 1.获取到对应的队列
CoroutineLockQueueType coroutineLockQueueType = self.list[coroutineLockType];
// 2.如果不存在这个队列,说明不需要排队等待
if (!coroutineLockQueueType.TryGetValue(key, out CoroutineLockQueue queue))
{
// 2.1直接返回CoroutineLock
coroutineLockQueueType.Add(key, self.AddChildWithId<CoroutineLockQueue>(++self.idGenerator, true));
return self.CreateCoroutineLock(coroutineLockType, key, time, 1);
}
// 3.加入排队队列
ETTask<CoroutineLock> tcs = ETTask<CoroutineLock>.Create(true);
queue.Add(tcs, time);
return await tcs;
}
List的结构如下
总的来说就是一个List<Dic<Type,Queue»结构
首先对不同类型的CoroutineLockType划分不同的字典,每一个字典中又对不同的Key维护了不同的队列
内部对不同的Key划分了不同的Queue,Key象征的一把锁,同一把锁的调用自然需要进入同一类型的Queue中排队
public List<CoroutineLockQueueType> list;
public class CoroutineLockQueueType: Entity, IAwake, IDestroy
{
public Dictionary<long, CoroutineLockQueue> dictionary;
}
public class CoroutineLockQueue: Entity, IAwake, IDestroy
{
public Queue<CoroutineLockInfo> queue = new Queue<CoroutineLockInfo>();
}
public struct CoroutineLockInfo
{
public ETTask<CoroutineLock> Tcs;
public int Time;
}
至于锁队列,依赖两部分驱动
一部分是超时处理,这部分在Update中,会定期处理超时的锁,并推进Queue
当然这属于“异常”了,另外一个推进的地方则是在某一个CoroutineLock被销毁时
此时也会推进某一个Queue
因此我们在用完之后,必须对锁进行销毁