TimerComponent.cs 7.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Threading;
  4. namespace ET
  5. {
  6. public interface ITimer
  7. {
  8. void Run();
  9. }
  10. [ObjectSystem]
  11. public class OnceWaitTimerAwakeSystem : AwakeSystem<OnceWaitTimer, ETTaskCompletionSource>
  12. {
  13. public override void Awake(OnceWaitTimer self, ETTaskCompletionSource callback)
  14. {
  15. self.Callback = callback;
  16. }
  17. }
  18. public class OnceWaitTimer: Entity, ITimer
  19. {
  20. public ETTaskCompletionSource Callback { get; set; }
  21. public void Run()
  22. {
  23. ETTaskCompletionSource tcs = this.Callback;
  24. this.GetParent<TimerComponent>().Remove(this.Id);
  25. tcs.SetResult();
  26. }
  27. }
  28. [ObjectSystem]
  29. public class OnceTimerAwakeSystem : AwakeSystem<OnceTimer, Action>
  30. {
  31. public override void Awake(OnceTimer self, Action callback)
  32. {
  33. self.Callback = callback;
  34. }
  35. }
  36. public class OnceTimer: Entity, ITimer
  37. {
  38. public Action Callback { get; set; }
  39. public void Run()
  40. {
  41. try
  42. {
  43. this.Callback.Invoke();
  44. }
  45. catch (Exception e)
  46. {
  47. Log.Error(e);
  48. }
  49. }
  50. }
  51. [ObjectSystem]
  52. public class RepeatedTimerAwakeSystem : AwakeSystem<RepeatedTimer, long, Action>
  53. {
  54. public override void Awake(RepeatedTimer self, long repeatedTime, Action callback)
  55. {
  56. self.Awake(repeatedTime, callback);
  57. }
  58. }
  59. public class RepeatedTimer: Entity, ITimer
  60. {
  61. public void Awake(long repeatedTime, Action 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 Callback { private get; set; }
  73. public void Run()
  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();
  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();
  174. }
  175. }
  176. public ETTask WaitTillAsync(long tillTime, ETCancellationToken cancellationToken)
  177. {
  178. if (TimeHelper.Now() > tillTime)
  179. {
  180. return ETTask.CompletedTask;
  181. }
  182. ETTaskCompletionSource tcs = new ETTaskCompletionSource();
  183. OnceWaitTimer timer = EntityFactory.CreateWithParent<OnceWaitTimer, ETTaskCompletionSource>(this, tcs);
  184. this.timers[timer.Id] = timer;
  185. AddToTimeId(tillTime, timer.Id);
  186. cancellationToken.Register(() => { this.Remove(timer.Id); });
  187. return tcs.Task;
  188. }
  189. public ETTask WaitTillAsync(long tillTime)
  190. {
  191. if (TimeHelper.Now() > tillTime)
  192. {
  193. return ETTask.CompletedTask;
  194. }
  195. ETTaskCompletionSource tcs = new ETTaskCompletionSource();
  196. OnceWaitTimer timer = EntityFactory.CreateWithParent<OnceWaitTimer, ETTaskCompletionSource>(this, tcs);
  197. this.timers[timer.Id] = timer;
  198. AddToTimeId(tillTime, timer.Id);
  199. return tcs.Task;
  200. }
  201. public ETTask WaitAsync(long time, ETCancellationToken cancellationToken)
  202. {
  203. long tillTime = TimeHelper.Now() + time;
  204. if (TimeHelper.Now() > tillTime)
  205. {
  206. return ETTask.CompletedTask;
  207. }
  208. ETTaskCompletionSource tcs = new ETTaskCompletionSource();
  209. OnceWaitTimer timer = EntityFactory.CreateWithParent<OnceWaitTimer, ETTaskCompletionSource>(this, tcs);
  210. this.timers[timer.Id] = timer;
  211. AddToTimeId(tillTime, timer.Id);
  212. cancellationToken.Register(() => { this.Remove(timer.Id); });
  213. return tcs.Task;
  214. }
  215. public ETTask WaitAsync(long time)
  216. {
  217. long tillTime = TimeHelper.Now() + time;
  218. ETTaskCompletionSource tcs = new ETTaskCompletionSource();
  219. OnceWaitTimer timer = EntityFactory.CreateWithParent<OnceWaitTimer, ETTaskCompletionSource>(this, tcs);
  220. this.timers[timer.Id] = timer;
  221. AddToTimeId(tillTime, timer.Id);
  222. return tcs.Task;
  223. }
  224. /// <summary>
  225. /// 创建一个RepeatedTimer
  226. /// </summary>
  227. /// <param name="time"></param>
  228. /// <param name="action"></param>
  229. /// <returns></returns>
  230. public long NewRepeatedTimer(long time, Action action)
  231. {
  232. if (time < 30)
  233. {
  234. throw new Exception($"repeated time < 30");
  235. }
  236. long tillTime = TimeHelper.Now() + time;
  237. RepeatedTimer timer = EntityFactory.CreateWithParent<RepeatedTimer, long, Action>(this, time, action);
  238. this.timers[timer.Id] = timer;
  239. AddToTimeId(tillTime, timer.Id);
  240. return timer.Id;
  241. }
  242. public RepeatedTimer GetRepeatedTimer(long id)
  243. {
  244. if (!this.timers.TryGetValue(id, out ITimer timer))
  245. {
  246. return null;
  247. }
  248. return timer as RepeatedTimer;
  249. }
  250. public void Remove(long id)
  251. {
  252. if (id == 0)
  253. {
  254. return;
  255. }
  256. ITimer timer;
  257. if (!this.timers.TryGetValue(id, out timer))
  258. {
  259. return;
  260. }
  261. this.timers.Remove(id);
  262. (timer as IDisposable)?.Dispose();
  263. }
  264. public long NewOnceTimer(long tillTime, Action action)
  265. {
  266. OnceTimer timer = EntityFactory.CreateWithParent<OnceTimer, Action>(this, action);
  267. this.timers[timer.Id] = timer;
  268. AddToTimeId(tillTime, timer.Id);
  269. return timer.Id;
  270. }
  271. public OnceTimer GetOnceTimer(long id)
  272. {
  273. if (!this.timers.TryGetValue(id, out ITimer timer))
  274. {
  275. return null;
  276. }
  277. return timer as OnceTimer;
  278. }
  279. public void AddToTimeId(long tillTime, long id)
  280. {
  281. this.TimeId.Add(tillTime, id);
  282. if (tillTime < this.minTime)
  283. {
  284. this.minTime = tillTime;
  285. }
  286. }
  287. }
  288. }