TimerComponent.cs 7.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Threading;
  4. namespace ET
  5. {
  6. public interface ITimer
  7. {
  8. void Run(bool isTimeout);
  9. }
  10. [ObjectSystem]
  11. public class OnceWaitTimerAwakeSystem : AwakeSystem<OnceWaitTimer, ETTaskCompletionSource<bool>>
  12. {
  13. public override void Awake(OnceWaitTimer self, ETTaskCompletionSource<bool> callback)
  14. {
  15. self.Callback = callback;
  16. }
  17. }
  18. public class OnceWaitTimer: Entity, ITimer
  19. {
  20. public ETTaskCompletionSource<bool> Callback { get; set; }
  21. public void Run(bool isTimeout)
  22. {
  23. ETTaskCompletionSource<bool> tcs = this.Callback;
  24. this.GetParent<TimerComponent>().Remove(this.Id);
  25. tcs.SetResult(isTimeout);
  26. }
  27. }
  28. [ObjectSystem]
  29. public class OnceTimerAwakeSystem : AwakeSystem<OnceTimer, Action<bool>>
  30. {
  31. public override void Awake(OnceTimer self, Action<bool> callback)
  32. {
  33. self.Callback = callback;
  34. }
  35. }
  36. public class OnceTimer: Entity, ITimer
  37. {
  38. public Action<bool> Callback { get; set; }
  39. public void Run(bool isTimeout)
  40. {
  41. try
  42. {
  43. this.Callback.Invoke(isTimeout);
  44. }
  45. catch (Exception e)
  46. {
  47. Log.Error(e);
  48. }
  49. }
  50. }
  51. [ObjectSystem]
  52. public class RepeatedTimerAwakeSystem : AwakeSystem<RepeatedTimer, long, Action<bool>>
  53. {
  54. public override void Awake(RepeatedTimer self, long repeatedTime, Action<bool> callback)
  55. {
  56. self.Awake(repeatedTime, callback);
  57. }
  58. }
  59. public class RepeatedTimer: Entity, ITimer
  60. {
  61. public void Awake(long repeatedTime, Action<bool> callback)
  62. {
  63. this.StartTime = TimeHelper.Now();
  64. this.RepeatedTime = repeatedTime;
  65. this.Callback = callback;
  66. this.Count = 1;
  67. }
  68. private long StartTime { get; set; }
  69. private long RepeatedTime { get; set; }
  70. // 下次一是第几次触发
  71. private int Count { get; set; }
  72. public Action<bool> Callback { private get; set; }
  73. public void Run(bool isTimeout)
  74. {
  75. ++this.Count;
  76. TimerComponent timerComponent = this.GetParent<TimerComponent>();
  77. long tillTime = this.StartTime + this.RepeatedTime * this.Count;
  78. timerComponent.AddToTimeId(tillTime, this.Id);
  79. try
  80. {
  81. this.Callback?.Invoke(isTimeout);
  82. }
  83. catch (Exception e)
  84. {
  85. Log.Error(e);
  86. }
  87. }
  88. public override void Dispose()
  89. {
  90. if (this.IsDisposed)
  91. {
  92. return;
  93. }
  94. long id = this.Id;
  95. if (id == 0)
  96. {
  97. Log.Error($"RepeatedTimer可能多次释放了");
  98. return;
  99. }
  100. base.Dispose();
  101. this.StartTime = 0;
  102. this.RepeatedTime = 0;
  103. this.Callback = null;
  104. this.Count = 0;
  105. }
  106. }
  107. [ObjectSystem]
  108. public class TimerComponentAwakeSystem : AwakeSystem<TimerComponent>
  109. {
  110. public override void Awake(TimerComponent self)
  111. {
  112. TimerComponent.Instance = self;
  113. }
  114. }
  115. [ObjectSystem]
  116. public class TimerComponentUpdateSystem : UpdateSystem<TimerComponent>
  117. {
  118. public override void Update(TimerComponent self)
  119. {
  120. self.Update();
  121. }
  122. }
  123. public class TimerComponent : Entity
  124. {
  125. public static TimerComponent Instance { get; set; }
  126. private readonly Dictionary<long, ITimer> timers = new Dictionary<long, ITimer>();
  127. /// <summary>
  128. /// key: time, value: timer id
  129. /// </summary>
  130. public readonly MultiMap<long, long> TimeId = new MultiMap<long, long>();
  131. private readonly Queue<long> timeOutTime = new Queue<long>();
  132. private readonly Queue<long> timeOutTimerIds = new Queue<long>();
  133. // 记录最小时间,不用每次都去MultiMap取第一个值
  134. private long minTime;
  135. public void Update()
  136. {
  137. if (this.TimeId.Count == 0)
  138. {
  139. return;
  140. }
  141. long timeNow = TimeHelper.Now();
  142. if (timeNow < this.minTime)
  143. {
  144. return;
  145. }
  146. foreach (KeyValuePair<long, List<long>> kv in this.TimeId.GetDictionary())
  147. {
  148. long k = kv.Key;
  149. if (k > timeNow)
  150. {
  151. minTime = k;
  152. break;
  153. }
  154. this.timeOutTime.Enqueue(k);
  155. }
  156. while(this.timeOutTime.Count > 0)
  157. {
  158. long time = this.timeOutTime.Dequeue();
  159. foreach(long timerId in this.TimeId[time])
  160. {
  161. this.timeOutTimerIds.Enqueue(timerId);
  162. }
  163. this.TimeId.Remove(time);
  164. }
  165. while(this.timeOutTimerIds.Count > 0)
  166. {
  167. long timerId = this.timeOutTimerIds.Dequeue();
  168. ITimer timer;
  169. if (!this.timers.TryGetValue(timerId, out timer))
  170. {
  171. continue;
  172. }
  173. timer.Run(true);
  174. }
  175. }
  176. public async ETTask<bool> WaitTillAsync(long tillTime, ETCancellationToken cancellationToken)
  177. {
  178. if (TimeHelper.Now() > tillTime)
  179. {
  180. return true;
  181. }
  182. ETTaskCompletionSource<bool> tcs = new ETTaskCompletionSource<bool>();
  183. OnceWaitTimer timer = EntityFactory.CreateWithParent<OnceWaitTimer, ETTaskCompletionSource<bool>>(this, tcs);
  184. this.timers[timer.Id] = timer;
  185. AddToTimeId(tillTime, timer.Id);
  186. long instanceId = timer.InstanceId;
  187. cancellationToken.Register(() =>
  188. {
  189. if (instanceId != timer.InstanceId)
  190. {
  191. return;
  192. }
  193. timer.Run(false);
  194. this.Remove(timer.Id);
  195. });
  196. return await tcs.Task;
  197. }
  198. public async ETTask<bool> WaitTillAsync(long tillTime)
  199. {
  200. if (TimeHelper.Now() > tillTime)
  201. {
  202. return true;
  203. }
  204. ETTaskCompletionSource<bool> tcs = new ETTaskCompletionSource<bool>();
  205. OnceWaitTimer timer = EntityFactory.CreateWithParent<OnceWaitTimer, ETTaskCompletionSource<bool>>(this, tcs);
  206. this.timers[timer.Id] = timer;
  207. AddToTimeId(tillTime, timer.Id);
  208. return await tcs.Task;
  209. }
  210. public async ETTask<bool> WaitAsync(long time, ETCancellationToken cancellationToken)
  211. {
  212. long tillTime = TimeHelper.Now() + time;
  213. if (TimeHelper.Now() > tillTime)
  214. {
  215. return true;
  216. }
  217. ETTaskCompletionSource<bool> tcs = new ETTaskCompletionSource<bool>();
  218. OnceWaitTimer timer = EntityFactory.CreateWithParent<OnceWaitTimer, ETTaskCompletionSource<bool>>(this, tcs);
  219. this.timers[timer.Id] = timer;
  220. AddToTimeId(tillTime, timer.Id);
  221. long instanceId = timer.InstanceId;
  222. cancellationToken.Register(() =>
  223. {
  224. if (instanceId != timer.InstanceId)
  225. {
  226. return;
  227. }
  228. timer.Run(false);
  229. this.Remove(timer.Id);
  230. });
  231. return await tcs.Task;
  232. }
  233. public async ETTask<bool> WaitAsync(long time)
  234. {
  235. long tillTime = TimeHelper.Now() + time;
  236. ETTaskCompletionSource<bool> tcs = new ETTaskCompletionSource<bool>();
  237. OnceWaitTimer timer = EntityFactory.CreateWithParent<OnceWaitTimer, ETTaskCompletionSource<bool>>(this, tcs);
  238. this.timers[timer.Id] = timer;
  239. AddToTimeId(tillTime, timer.Id);
  240. return await tcs.Task;
  241. }
  242. /// <summary>
  243. /// 创建一个RepeatedTimer
  244. /// </summary>
  245. /// <param name="time"></param>
  246. /// <param name="action"></param>
  247. /// <returns></returns>
  248. public long NewRepeatedTimer(long time, Action<bool> action)
  249. {
  250. if (time < 30)
  251. {
  252. throw new Exception($"repeated time < 30");
  253. }
  254. long tillTime = TimeHelper.Now() + time;
  255. RepeatedTimer timer = EntityFactory.CreateWithParent<RepeatedTimer, long, Action<bool>>(this, time, action);
  256. this.timers[timer.Id] = timer;
  257. AddToTimeId(tillTime, timer.Id);
  258. return timer.Id;
  259. }
  260. public RepeatedTimer GetRepeatedTimer(long id)
  261. {
  262. if (!this.timers.TryGetValue(id, out ITimer timer))
  263. {
  264. return null;
  265. }
  266. return timer as RepeatedTimer;
  267. }
  268. public void Remove(long id)
  269. {
  270. if (id == 0)
  271. {
  272. return;
  273. }
  274. ITimer timer;
  275. if (!this.timers.TryGetValue(id, out timer))
  276. {
  277. return;
  278. }
  279. this.timers.Remove(id);
  280. (timer as IDisposable)?.Dispose();
  281. }
  282. public long NewOnceTimer(long tillTime, Action action)
  283. {
  284. OnceTimer timer = EntityFactory.CreateWithParent<OnceTimer, Action>(this, action);
  285. this.timers[timer.Id] = timer;
  286. AddToTimeId(tillTime, timer.Id);
  287. return timer.Id;
  288. }
  289. public OnceTimer GetOnceTimer(long id)
  290. {
  291. if (!this.timers.TryGetValue(id, out ITimer timer))
  292. {
  293. return null;
  294. }
  295. return timer as OnceTimer;
  296. }
  297. public void AddToTimeId(long tillTime, long id)
  298. {
  299. this.TimeId.Add(tillTime, id);
  300. if (tillTime < this.minTime)
  301. {
  302. this.minTime = tillTime;
  303. }
  304. }
  305. }
  306. }