소스 검색

1.无GC ETTask,其实是利用对象池,注意,必须小心使用,不懂不要乱用
2.超时协程锁,并且修复了一个协程锁队列递归调用导致堆栈溢出的bug

tanghai 4 년 전
부모
커밋
e2099974e6
35개의 변경된 파일747개의 추가작업 그리고 542개의 파일을 삭제
  1. 2 2
      Server/Hotfix/Module/Actor/ActorMessageSenderComponentSystem.cs
  2. 2 2
      Server/Model/Module/Actor/ActorMessageSender.cs
  3. 0 6
      Server/Model/Server.Model.csproj
  4. 2 2
      Unity/Assets/Hotfix/Demo/Move/MoveComponentSystem.cs
  5. 3 3
      Unity/Assets/HotfixView/Scene/SceneChangeComponentSystem.cs
  6. 0 9
      Unity/Assets/Model/Base.meta
  7. 6 0
      Unity/Assets/Model/Core/Async/AsyncETTaskCompletedMethodBuilder.cs
  8. 24 10
      Unity/Assets/Model/Core/Async/AsyncETTaskMethodBuilder.cs
  9. 7 0
      Unity/Assets/Model/Core/Async/AsyncETVoidMethodBuilder.cs
  10. 4 4
      Unity/Assets/Model/Core/Async/AsyncMethodBuilderAttribute.cs
  11. 5 10
      Unity/Assets/Model/Core/Async/ETCancellationToken.cs
  12. 282 20
      Unity/Assets/Model/Core/Async/ETTask.cs
  13. 3 0
      Unity/Assets/Model/Core/Async/ETTaskCompleted.cs
  14. 0 227
      Unity/Assets/Model/Core/Async/ETTaskCompletionSource.cs
  15. 0 11
      Unity/Assets/Model/Core/Async/ETTaskCompletionSource.cs.meta
  16. 103 28
      Unity/Assets/Model/Core/Async/ETTaskHelper.cs
  17. 2 0
      Unity/Assets/Model/Core/Async/ETVoid.cs
  18. 1 1
      Unity/Assets/Model/Core/Async/IAwaiter.cs
  19. 5 5
      Unity/Assets/Model/Core/Entity/TimerComponent.cs
  20. 4 4
      Unity/Assets/Model/Core/ObjectWait.cs
  21. 8 15
      Unity/Assets/Model/Core/Options.cs
  22. 1 1
      Unity/Assets/Model/Core/Options.cs.meta
  23. 13 21
      Unity/Assets/Model/Module/CoroutineLock/CoroutineLock.cs
  24. 201 23
      Unity/Assets/Model/Module/CoroutineLock/CoroutineLockComponent.cs
  25. 0 39
      Unity/Assets/Model/Module/CoroutineLock/CoroutineLockQueue.cs
  26. 0 11
      Unity/Assets/Model/Module/CoroutineLock/CoroutineLockQueue.cs.meta
  27. 0 36
      Unity/Assets/Model/Module/CoroutineLock/CoroutineLockQueueType.cs
  28. 0 11
      Unity/Assets/Model/Module/CoroutineLock/CoroutineLockQueueType.cs.meta
  29. 3 12
      Unity/Assets/Model/Module/CoroutineLock/CoroutineLockType.cs
  30. 4 4
      Unity/Assets/Model/Module/Message/Session.cs
  31. 1 1
      Unity/Assets/Model/Module/Network/KChannel.cs
  32. 2 2
      Unity/Assets/Model/Module/Resource/ResourcesComponent.cs
  33. 3 3
      Unity/Assets/Model/Module/UnityWebRequest/UnityWebRequestAsync.cs
  34. 55 18
      Unity/Assets/Model/Module/UnityWebRequest/UnityWebRequestRenewalAsync.cs
  35. 1 1
      Unity/Assets/ModelView/Scene/SceneChangeComponent.cs

+ 2 - 2
Server/Hotfix/Module/Actor/ActorMessageSenderComponentSystem.cs

@@ -139,14 +139,14 @@ namespace ET
                 throw new Exception($"actor id is 0: {memoryStream.ToActorMessage()}");
             }
 
-            var tcs = new ETTaskCompletionSource<IActorResponse>();
+            var tcs = ETTask<IActorResponse>.Create(true);
             
             self.requestCallback.Add(rpcId, new ActorMessageSender(actorId, memoryStream, tcs, needException));
             
             self.Send(actorId, memoryStream);
 
             long beginTime = TimeHelper.ServerFrameTime();
-            IActorResponse response = await tcs.Task;
+            IActorResponse response = await tcs;
             long endTime = TimeHelper.ServerFrameTime();
 
             long costTime = endTime - beginTime;

+ 2 - 2
Server/Model/Module/Actor/ActorMessageSender.cs

@@ -14,9 +14,9 @@ namespace ET
 
         public bool NeedException { get; }
 
-        public ETTaskCompletionSource<IActorResponse> Tcs { get; }
+        public ETTask<IActorResponse> Tcs { get; }
 
-        public ActorMessageSender(long actorId, MemoryStream memoryStream, ETTaskCompletionSource<IActorResponse> tcs, bool needException)
+        public ActorMessageSender(long actorId, MemoryStream memoryStream, ETTask<IActorResponse> tcs, bool needException)
         {
             this.ActorId = actorId;
             this.MemoryStream = memoryStream;

+ 0 - 6
Server/Model/Server.Model.csproj

@@ -59,12 +59,6 @@
     <Compile Include="..\..\Unity\Assets\Model\Module\CoroutineLock\CoroutineLockComponent.cs">
       <Link>Module\CoroutineLock\CoroutineLockComponent.cs</Link>
     </Compile>
-    <Compile Include="..\..\Unity\Assets\Model\Module\CoroutineLock\CoroutineLockQueue.cs">
-      <Link>Module\CoroutineLock\CoroutineLockQueue.cs</Link>
-    </Compile>
-    <Compile Include="..\..\Unity\Assets\Model\Module\CoroutineLock\CoroutineLockQueueType.cs">
-      <Link>Module\CoroutineLock\CoroutineLockQueueType.cs</Link>
-    </Compile>
     <Compile Include="..\..\Unity\Assets\Model\Module\CoroutineLock\CoroutineLockType.cs">
       <Link>Module\CoroutineLock\CoroutineLockType.cs</Link>
     </Compile>

+ 2 - 2
Unity/Assets/Hotfix/Demo/Move/MoveComponentSystem.cs

@@ -77,7 +77,7 @@ namespace ET
             self.IsTurnHorizontal = true;
             self.TurnTime = turnTime;
             self.Speed = speed;
-            ETTaskCompletionSource<bool> tcs = new ETTaskCompletionSource<bool>();
+            ETTask<bool> tcs = ETTask<bool>.Create(true);
             self.Callback = (ret) => { tcs.SetResult(ret); };
 
             Game.EventSystem.Publish(new EventType.MoveStart(){Unit = self.GetParent<Unit>()}).Coroutine();
@@ -93,7 +93,7 @@ namespace ET
             try
             {
                 cancellationToken?.Add(CancelAction);
-                moveRet = await tcs.Task;
+                moveRet = await tcs;
             }
             finally
             {

+ 3 - 3
Unity/Assets/HotfixView/Scene/SceneChangeComponentSystem.cs

@@ -16,7 +16,7 @@ namespace ET
                 return;
             }
             
-            ETTaskCompletionSource tcs = self.tcs;
+            ETTask tcs = self.tcs;
             self.tcs = null;
             tcs.SetResult();
         }
@@ -36,11 +36,11 @@ namespace ET
     {
         public static async ETTask ChangeSceneAsync(this SceneChangeComponent self, string sceneName)
         {
-            self.tcs = new ETTaskCompletionSource();
+            self.tcs = ETTask.Create(true);
             // 加载map
             self.loadMapOperation = SceneManager.LoadSceneAsync(sceneName);
             //this.loadMapOperation.allowSceneActivation = false;
-            await self.tcs.Task;
+            await self.tcs;
         }
         
         public static int Process(this SceneChangeComponent self)

+ 0 - 9
Unity/Assets/Model/Base.meta

@@ -1,9 +0,0 @@
-fileFormatVersion: 2
-guid: 5a0e66833e8706d4bb62a6486e57b0b3
-folderAsset: yes
-timeCreated: 1495185207
-licenseType: Pro
-DefaultImporter:
-  userData: 
-  assetBundleName: 
-  assetBundleVariant: 

+ 6 - 0
Unity/Assets/Model/Core/Async/AsyncETTaskCompletedMethodBuilder.cs

@@ -19,6 +19,7 @@ namespace ET
         public ETTaskCompleted Task => default;
 
         // 3. SetException
+        [MethodImpl(MethodImplOptions.AggressiveInlining)]
         [DebuggerHidden]
         public void SetException(Exception exception)
         {
@@ -26,6 +27,7 @@ namespace ET
         }
 
         // 4. SetResult
+        [MethodImpl(MethodImplOptions.AggressiveInlining)]
         [DebuggerHidden]
         public void SetResult()
         {
@@ -33,6 +35,7 @@ namespace ET
         }
 
         // 5. AwaitOnCompleted
+        [MethodImpl(MethodImplOptions.AggressiveInlining)]
         [DebuggerHidden]
         public void AwaitOnCompleted<TAwaiter, TStateMachine>(ref TAwaiter awaiter, ref TStateMachine stateMachine) where TAwaiter : INotifyCompletion where TStateMachine : IAsyncStateMachine
         {
@@ -40,6 +43,7 @@ namespace ET
         }
 
         // 6. AwaitUnsafeOnCompleted
+        [MethodImpl(MethodImplOptions.AggressiveInlining)]
         [DebuggerHidden]
         [SecuritySafeCritical]
         public void AwaitUnsafeOnCompleted<TAwaiter, TStateMachine>(ref TAwaiter awaiter, ref TStateMachine stateMachine) where TAwaiter : ICriticalNotifyCompletion where TStateMachine : IAsyncStateMachine
@@ -48,6 +52,7 @@ namespace ET
         }
 
         // 7. Start
+        [MethodImpl(MethodImplOptions.AggressiveInlining)]
         [DebuggerHidden]
         public void Start<TStateMachine>(ref TStateMachine stateMachine) where TStateMachine : IAsyncStateMachine
         {
@@ -55,6 +60,7 @@ namespace ET
         }
 
         // 8. SetStateMachine
+        [MethodImpl(MethodImplOptions.AggressiveInlining)]
         [DebuggerHidden]
         public void SetStateMachine(IAsyncStateMachine stateMachine)
         {

+ 24 - 10
Unity/Assets/Model/Core/Async/AsyncETTaskMethodBuilder.cs

@@ -7,35 +7,39 @@ namespace ET
 {
     public struct ETAsyncTaskMethodBuilder
     {
-        public ETTaskCompletionSource Tcs;
+        private ETTask tcs;
 
         // 1. Static Create method.
         [DebuggerHidden]
+        [MethodImpl(MethodImplOptions.AggressiveInlining)]
         public static ETAsyncTaskMethodBuilder Create()
         {
-            ETAsyncTaskMethodBuilder builder = new ETAsyncTaskMethodBuilder() { Tcs = new ETTaskCompletionSource() };
+            ETAsyncTaskMethodBuilder builder = new ETAsyncTaskMethodBuilder() { tcs = ETTask.Create(true) };
             return builder;
         }
 
         // 2. TaskLike Task property.
         [DebuggerHidden]
-        public ETTask Task => this.Tcs.Task;
+        public ETTask Task => this.tcs;
 
         // 3. SetException
+        [MethodImpl(MethodImplOptions.AggressiveInlining)]
         [DebuggerHidden]
         public void SetException(Exception exception)
         {
-            this.Tcs.SetException(exception);
+            this.tcs.SetException(exception);
         }
 
         // 4. SetResult
         [DebuggerHidden]
+        [MethodImpl(MethodImplOptions.AggressiveInlining)]
         public void SetResult()
         {
-            this.Tcs.SetResult();
+            this.tcs.SetResult();
         }
 
         // 5. AwaitOnCompleted
+        [MethodImpl(MethodImplOptions.AggressiveInlining)]
         [DebuggerHidden]
         public void AwaitOnCompleted<TAwaiter, TStateMachine>(ref TAwaiter awaiter, ref TStateMachine stateMachine) where TAwaiter : INotifyCompletion where TStateMachine : IAsyncStateMachine
         {
@@ -43,6 +47,7 @@ namespace ET
         }
 
         // 6. AwaitUnsafeOnCompleted
+        [MethodImpl(MethodImplOptions.AggressiveInlining)]
         [DebuggerHidden]
         [SecuritySafeCritical]
         public void AwaitUnsafeOnCompleted<TAwaiter, TStateMachine>(ref TAwaiter awaiter, ref TStateMachine stateMachine) where TAwaiter : ICriticalNotifyCompletion where TStateMachine : IAsyncStateMachine
@@ -52,6 +57,7 @@ namespace ET
 
         // 7. Start
         [DebuggerHidden]
+        [MethodImpl(MethodImplOptions.AggressiveInlining)]
         public void Start<TStateMachine>(ref TStateMachine stateMachine) where TStateMachine : IAsyncStateMachine
         {
             stateMachine.MoveNext();
@@ -59,6 +65,7 @@ namespace ET
 
         // 8. SetStateMachine
         [DebuggerHidden]
+        [MethodImpl(MethodImplOptions.AggressiveInlining)]
         public void SetStateMachine(IAsyncStateMachine stateMachine)
         {
         }
@@ -66,42 +73,47 @@ namespace ET
 
     public struct ETAsyncTaskMethodBuilder<T>
     {
-        public ETTaskCompletionSource<T> Tcs;
+        private ETTask<T> tcs;
 
         // 1. Static Create method.
         [DebuggerHidden]
+        [MethodImpl(MethodImplOptions.AggressiveInlining)]
         public static ETAsyncTaskMethodBuilder<T> Create()
         {
-            ETAsyncTaskMethodBuilder<T> builder = new ETAsyncTaskMethodBuilder<T>() { Tcs = new ETTaskCompletionSource<T>() };
+            ETAsyncTaskMethodBuilder<T> builder = new ETAsyncTaskMethodBuilder<T>() { tcs = ETTask<T>.Create(true) };
             return builder;
         }
 
         // 2. TaskLike Task property.
         [DebuggerHidden]
-        public ETTask<T> Task => this.Tcs.Task;
+        public ETTask<T> Task => this.tcs;
 
         // 3. SetException
         [DebuggerHidden]
+        [MethodImpl(MethodImplOptions.AggressiveInlining)]
         public void SetException(Exception exception)
         {
-            this.Tcs.SetException(exception);
+            this.tcs.SetException(exception);
         }
 
         // 4. SetResult
         [DebuggerHidden]
+        [MethodImpl(MethodImplOptions.AggressiveInlining)]
         public void SetResult(T ret)
         {
-            this.Tcs.SetResult(ret);
+            this.tcs.SetResult(ret);
         }
 
         // 5. AwaitOnCompleted
         [DebuggerHidden]
+        [MethodImpl(MethodImplOptions.AggressiveInlining)]
         public void AwaitOnCompleted<TAwaiter, TStateMachine>(ref TAwaiter awaiter, ref TStateMachine stateMachine) where TAwaiter : INotifyCompletion where TStateMachine : IAsyncStateMachine
         {
             awaiter.OnCompleted(stateMachine.MoveNext);
         }
 
         // 6. AwaitUnsafeOnCompleted
+        [MethodImpl(MethodImplOptions.AggressiveInlining)]
         [DebuggerHidden]
         [SecuritySafeCritical]
         public void AwaitUnsafeOnCompleted<TAwaiter, TStateMachine>(ref TAwaiter awaiter, ref TStateMachine stateMachine) where TAwaiter : ICriticalNotifyCompletion where TStateMachine : IAsyncStateMachine
@@ -110,6 +122,7 @@ namespace ET
         }
 
         // 7. Start
+        [MethodImpl(MethodImplOptions.AggressiveInlining)]
         [DebuggerHidden]
         public void Start<TStateMachine>(ref TStateMachine stateMachine) where TStateMachine : IAsyncStateMachine
         {
@@ -117,6 +130,7 @@ namespace ET
         }
 
         // 8. SetStateMachine
+        [MethodImpl(MethodImplOptions.AggressiveInlining)]
         [DebuggerHidden]
         public void SetStateMachine(IAsyncStateMachine stateMachine)
         {

+ 7 - 0
Unity/Assets/Model/Core/Async/AsyncETVoidMethodBuilder.cs

@@ -8,6 +8,7 @@ namespace ET
     public struct AsyncETVoidMethodBuilder
     {
         // 1. Static Create method.
+        [MethodImpl(MethodImplOptions.AggressiveInlining)]
         [DebuggerHidden]
         public static AsyncETVoidMethodBuilder Create()
         {
@@ -20,6 +21,7 @@ namespace ET
         public ETVoid Task => default;
 
         // 3. SetException
+        [MethodImpl(MethodImplOptions.AggressiveInlining)]
         [DebuggerHidden]
         public void SetException(Exception exception)
         {
@@ -27,6 +29,7 @@ namespace ET
         }
 
         // 4. SetResult
+        [MethodImpl(MethodImplOptions.AggressiveInlining)]
         [DebuggerHidden]
         public void SetResult()
         {
@@ -34,6 +37,7 @@ namespace ET
         }
 
         // 5. AwaitOnCompleted
+        [MethodImpl(MethodImplOptions.AggressiveInlining)]
         [DebuggerHidden]
         public void AwaitOnCompleted<TAwaiter, TStateMachine>(ref TAwaiter awaiter, ref TStateMachine stateMachine) where TAwaiter : INotifyCompletion where TStateMachine : IAsyncStateMachine
         {
@@ -41,6 +45,7 @@ namespace ET
         }
 
         // 6. AwaitUnsafeOnCompleted
+        [MethodImpl(MethodImplOptions.AggressiveInlining)]
         [DebuggerHidden]
         [SecuritySafeCritical]
         public void AwaitUnsafeOnCompleted<TAwaiter, TStateMachine>(ref TAwaiter awaiter, ref TStateMachine stateMachine) where TAwaiter : ICriticalNotifyCompletion where TStateMachine : IAsyncStateMachine
@@ -49,6 +54,7 @@ namespace ET
         }
 
         // 7. Start
+        [MethodImpl(MethodImplOptions.AggressiveInlining)]
         [DebuggerHidden]
         public void Start<TStateMachine>(ref TStateMachine stateMachine) where TStateMachine : IAsyncStateMachine
         {
@@ -56,6 +62,7 @@ namespace ET
         }
 
         // 8. SetStateMachine
+        [MethodImpl(MethodImplOptions.AggressiveInlining)]
         [DebuggerHidden]
         public void SetStateMachine(IAsyncStateMachine stateMachine)
         {

+ 4 - 4
Unity/Assets/Model/Core/Async/AsyncMethodBuilderAttribute.cs

@@ -1,6 +1,6 @@
-namespace System.Runtime.CompilerServices
+#if !SERVER
+namespace System.Runtime.CompilerServices
 {
-#if !NOT_CLIENT
     public sealed class AsyncMethodBuilderAttribute: Attribute
     {
         public Type BuilderType
@@ -13,5 +13,5 @@
             BuilderType = builderType;
         }
     }
-#endif
-}
+}
+#endif

+ 5 - 10
Unity/Assets/Model/Core/Async/ETCancellationToken.cs

@@ -18,17 +18,17 @@ namespace ET
             this.actions?.Remove(callback);
         }
 
+        public bool IsCancel()
+        {
+            return this.actions == null;
+        }
+
         public void Cancel()
         {
             if (this.actions == null)
             {
                 return;
             }
-            
-            if (this.actions.Count == 0)
-            {
-                return;
-            }
 
             this.Invoke();
         }
@@ -57,11 +57,6 @@ namespace ET
                 return;
             }
 
-            if (this.actions.Count == 0)
-            {
-                return;
-            }
-
             await TimerComponent.Instance.WaitAsync(afterTimeCancel);
             
             this.Invoke();

+ 282 - 20
Unity/Assets/Model/Core/Async/ETTask.cs

@@ -1,66 +1,328 @@
-using System.Diagnostics;
+using System;
+using System.Collections.Generic;
+using System.Diagnostics;
 using System.Runtime.CompilerServices;
+using System.Runtime.ExceptionServices;
 
 namespace ET
 {
     [AsyncMethodBuilder(typeof (ETAsyncTaskMethodBuilder))]
-    public struct ETTask
+    public class ETTask: ICriticalNotifyCompletion
     {
-        public static ETTaskCompleted CompletedTask => new ETTaskCompleted();
+        public static ETTaskCompleted CompletedTask
+        {
+            get
+            {
+                return new ETTaskCompleted();
+            }
+        }
 
-        private readonly ETTaskCompletionSource awaiter;
+        private static readonly Queue<ETTask> queue = new Queue<ETTask>();
 
-        [DebuggerHidden]
-        public ETTask(ETTaskCompletionSource awaiter)
+        /// <summary>
+        /// 请不要随便使用ETTask的对象池,除非你完全搞懂了ETTask!!!
+        /// 假如开启了池,await之后不能再操作ETTask,否则可能操作到再次从池中分配出来的ETTask,产生灾难性的后果
+        /// SetResult的时候请现将tcs置空,避免多次对同一个ETTask SetResult
+        /// </summary>
+        public static ETTask Create(bool fromPool = false)
+        {
+            if (!fromPool)
+            {
+                return new ETTask();
+            }
+            
+            if (queue.Count == 0)
+            {
+                return new ETTask() {fromPool = true};    
+            }
+            return queue.Dequeue();
+        }
+
+        private void Recycle()
         {
-            this.awaiter = awaiter;
+            if (!this.fromPool)
+            {
+                return;
+            }
+            
+            this.state = AwaiterStatus.Pending;
+            this.callback = null;
+            queue.Enqueue(this);
+            // 太多了,回收一下
+            if (queue.Count > 1000)
+            {
+                queue.Clear();
+            }
         }
 
+        private bool fromPool;
+        private AwaiterStatus state;
+        private object callback; // Action or ExceptionDispatchInfo
+
+        private ETTask()
+        {
+        }
+        
+        [MethodImpl(MethodImplOptions.AggressiveInlining)]
         [DebuggerHidden]
-        public ETTaskCompletionSource GetAwaiter()
+        private async ETVoid InnerCoroutine()
         {
-            return this.awaiter;
+            await this;
         }
 
+        [MethodImpl(MethodImplOptions.AggressiveInlining)]
         [DebuggerHidden]
         public void Coroutine()
         {
             InnerCoroutine().Coroutine();
         }
 
+        [MethodImpl(MethodImplOptions.AggressiveInlining)]
         [DebuggerHidden]
-        private async ETVoid InnerCoroutine()
+        public ETTask GetAwaiter()
         {
-            await this;
+            return this;
+        }
+
+        
+        public bool IsCompleted
+        {
+            [MethodImpl(MethodImplOptions.AggressiveInlining)]
+            [DebuggerHidden]
+            get
+            {
+                return this.state != AwaiterStatus.Pending;
+            }
+        }
+
+        [MethodImpl(MethodImplOptions.AggressiveInlining)]
+        [DebuggerHidden]
+        public void UnsafeOnCompleted(Action action)
+        {
+            if (this.state != AwaiterStatus.Pending)
+            {
+                action?.Invoke();
+                return;
+            }
+
+            this.callback = action;
+        }
+
+        [MethodImpl(MethodImplOptions.AggressiveInlining)]
+        [DebuggerHidden]
+        public void OnCompleted(Action action)
+        {
+            this.UnsafeOnCompleted(action);
+        }
+
+        [MethodImpl(MethodImplOptions.AggressiveInlining)]
+        [DebuggerHidden]
+        public void GetResult()
+        {
+            switch (this.state)
+            {
+                case AwaiterStatus.Succeeded:
+                    this.Recycle();
+                    break;
+                case AwaiterStatus.Faulted:
+                    ExceptionDispatchInfo c = this.callback as ExceptionDispatchInfo;
+                    this.callback = null;
+                    c?.Throw();
+                    this.Recycle();
+                    break;
+                default:
+                    throw new NotSupportedException("ETTask does not allow call GetResult directly when task not completed. Please use 'await'.");
+            }
+        }
+
+        [MethodImpl(MethodImplOptions.AggressiveInlining)]
+        [DebuggerHidden]
+        public void SetResult()
+        {
+            if (this.state != AwaiterStatus.Pending)
+            {
+                throw new InvalidOperationException("TaskT_TransitionToFinal_AlreadyCompleted");
+            }
+
+            this.state = AwaiterStatus.Succeeded;
+
+            Action c = this.callback as Action;
+            this.callback = null;
+            c?.Invoke();
+        }
+
+        [MethodImpl(MethodImplOptions.AggressiveInlining)]
+        [DebuggerHidden]
+        public void SetException(Exception e)
+        {
+            if (this.state != AwaiterStatus.Pending)
+            {
+                throw new InvalidOperationException("TaskT_TransitionToFinal_AlreadyCompleted");
+            }
+
+            this.state = AwaiterStatus.Faulted;
+
+            Action c = this.callback as Action;
+            this.callback = ExceptionDispatchInfo.Capture(e);
+            c?.Invoke();
         }
     }
 
     [AsyncMethodBuilder(typeof (ETAsyncTaskMethodBuilder<>))]
-    public struct ETTask<T>
+    public class ETTask<T>: ICriticalNotifyCompletion
     {
-        private readonly ETTaskCompletionSource<T> awaiter;
+        private static readonly Queue<ETTask<T>> queue = new Queue<ETTask<T>>();
+        
+        /// <summary>
+        /// 请不要随便使用ETTask的对象池,除非你完全搞懂了ETTask!!!
+        /// 假如开启了池,await之后不能再操作ETTask,否则可能操作到再次从池中分配出来的ETTask,产生灾难性的后果
+        /// SetResult的时候请现将tcs置空,避免多次对同一个ETTask SetResult
+        /// </summary>
+        public static ETTask<T> Create(bool fromPool = false)
+        {
+            if (!fromPool)
+            {
+                return new ETTask<T>();
+            }
+            
+            if (queue.Count == 0)
+            {
+                return new ETTask<T>() { fromPool = true };    
+            }
+            return queue.Dequeue();
+        }
+        
+        private void Recycle()
+        {
+            if (!this.fromPool)
+            {
+                return;
+            }
+            this.callback = null;
+            this.value = default;
+            this.state = AwaiterStatus.Pending;
+            queue.Enqueue(this);
+            // 太多了,回收一下
+            if (queue.Count > 1000)
+            {
+                queue.Clear();
+            }
+        }
 
-        [DebuggerHidden]
-        public ETTask(ETTaskCompletionSource<T> awaiter)
+        private bool fromPool;
+        private AwaiterStatus state;
+        private T value;
+        private object callback; // Action or ExceptionDispatchInfo
+
+        private ETTask()
         {
-            this.awaiter = awaiter;
         }
 
+        [MethodImpl(MethodImplOptions.AggressiveInlining)]
         [DebuggerHidden]
-        public ETTaskCompletionSource<T> GetAwaiter()
+        private async ETVoid InnerCoroutine()
         {
-            return this.awaiter;
+            await this;
         }
 
+        [MethodImpl(MethodImplOptions.AggressiveInlining)]
         [DebuggerHidden]
         public void Coroutine()
         {
             InnerCoroutine().Coroutine();
         }
 
-        private async ETVoid InnerCoroutine()
+        [MethodImpl(MethodImplOptions.AggressiveInlining)]
+        [DebuggerHidden]
+        public ETTask<T> GetAwaiter()
         {
-            await this;
+            return this;
+        }
+
+        [MethodImpl(MethodImplOptions.AggressiveInlining)]
+        [DebuggerHidden]
+        public T GetResult()
+        {
+            switch (this.state)
+            {
+                case AwaiterStatus.Succeeded:
+                    T v = this.value;
+                    this.Recycle();
+                    return v;
+                case AwaiterStatus.Faulted:
+                    ExceptionDispatchInfo c = this.callback as ExceptionDispatchInfo;
+                    this.callback = null;
+                    c?.Throw();
+                    this.Recycle();
+                    return default;
+                default:
+                    throw new NotSupportedException("ETask does not allow call GetResult directly when task not completed. Please use 'await'.");
+            }
+        }
+
+
+        public bool IsCompleted
+        {
+            [DebuggerHidden]
+            [MethodImpl(MethodImplOptions.AggressiveInlining)]
+            get
+            {
+                return state != AwaiterStatus.Pending;
+            }
+        } 
+
+        [MethodImpl(MethodImplOptions.AggressiveInlining)]
+        [DebuggerHidden]
+        public void UnsafeOnCompleted(Action action)
+        {
+            if (this.state != AwaiterStatus.Pending)
+            {
+                action?.Invoke();
+                return;
+            }
+
+            this.callback = action;
+        }
+
+        [MethodImpl(MethodImplOptions.AggressiveInlining)]
+        [DebuggerHidden]
+        public void OnCompleted(Action action)
+        {
+            this.UnsafeOnCompleted(action);
+        }
+
+        [MethodImpl(MethodImplOptions.AggressiveInlining)]
+        [DebuggerHidden]
+        public void SetResult(T result)
+        {
+            if (this.state != AwaiterStatus.Pending)
+            {
+                throw new InvalidOperationException("TaskT_TransitionToFinal_AlreadyCompleted");
+            }
+
+            this.state = AwaiterStatus.Succeeded;
+
+            this.value = result;
+
+            Action c = this.callback as Action;
+            this.callback = null;
+            c?.Invoke();
+        }
+
+        [MethodImpl(MethodImplOptions.AggressiveInlining)]
+        [DebuggerHidden]
+        public void SetException(Exception e)
+        {
+            if (this.state != AwaiterStatus.Pending)
+            {
+                throw new InvalidOperationException("TaskT_TransitionToFinal_AlreadyCompleted");
+            }
+
+            this.state = AwaiterStatus.Faulted;
+
+            Action c = this.callback as Action;
+            this.callback = ExceptionDispatchInfo.Capture(e);
+            c?.Invoke();
         }
     }
 }

+ 3 - 0
Unity/Assets/Model/Core/Async/ETTaskCompleted.cs

@@ -16,16 +16,19 @@ namespace ET
         [DebuggerHidden]
         public bool IsCompleted => true;
 
+        [MethodImpl(MethodImplOptions.AggressiveInlining)]
         [DebuggerHidden]
         public void GetResult()
         {
         }
 
+        [MethodImpl(MethodImplOptions.AggressiveInlining)]
         [DebuggerHidden]
         public void OnCompleted(Action continuation)
         {
         }
 
+        [MethodImpl(MethodImplOptions.AggressiveInlining)]
         [DebuggerHidden]
         public void UnsafeOnCompleted(Action continuation)
         {

+ 0 - 227
Unity/Assets/Model/Core/Async/ETTaskCompletionSource.cs

@@ -1,227 +0,0 @@
-using System;
-using System.Diagnostics;
-using System.Runtime.CompilerServices;
-using System.Runtime.ExceptionServices;
-
-namespace ET
-{
-    public class ETTaskCompletionSource: ICriticalNotifyCompletion
-    {
-        private AwaiterStatus state;
-        private ExceptionDispatchInfo exception;
-        private Action continuation; // action or list
-
-        [DebuggerHidden]
-        public ETTask Task => new ETTask(this);
-
-        [DebuggerHidden]
-        public AwaiterStatus Status => state;
-
-        [DebuggerHidden]
-        public bool IsCompleted => state != AwaiterStatus.Pending;
-
-        [DebuggerHidden]
-        public void UnsafeOnCompleted(Action action)
-        {
-            this.continuation = action;
-            if (state != AwaiterStatus.Pending)
-            {
-                TryInvokeContinuation();
-            }
-        }
-
-        [DebuggerHidden]
-        public void OnCompleted(Action action)
-        {
-            this.UnsafeOnCompleted(action);
-        }
-
-        [DebuggerHidden]
-        public void GetResult()
-        {
-            switch (this.state)
-            {
-                case AwaiterStatus.Succeeded:
-                    return;
-                case AwaiterStatus.Faulted:
-                    this.exception?.Throw();
-                    this.exception = null;
-                    return;
-                default:
-                    throw new NotSupportedException("ETTask does not allow call GetResult directly when task not completed. Please use 'await'.");
-            }
-        }
-
-        [DebuggerHidden]
-        public void SetResult()
-        {
-            if (this.TrySetResult())
-            {
-                return;
-            }
-
-            throw new InvalidOperationException("TaskT_TransitionToFinal_AlreadyCompleted");
-        }
-
-        [DebuggerHidden]
-        public void SetException(Exception e)
-        {
-            if (this.TrySetException(e))
-            {
-                return;
-            }
-
-            throw new InvalidOperationException("TaskT_TransitionToFinal_AlreadyCompleted");
-        }
-
-        [DebuggerHidden]
-        private void TryInvokeContinuation()
-        {
-            this.continuation?.Invoke();
-            this.continuation = null;
-        }
-
-        [DebuggerHidden]
-        private bool TrySetResult()
-        {
-            if (this.state != AwaiterStatus.Pending)
-            {
-                return false;
-            }
-
-            this.state = AwaiterStatus.Succeeded;
-
-            this.TryInvokeContinuation();
-            return true;
-        }
-
-        [DebuggerHidden]
-        private bool TrySetException(Exception e)
-        {
-            if (this.state != AwaiterStatus.Pending)
-            {
-                return false;
-            }
-
-            this.state = AwaiterStatus.Faulted;
-
-            this.exception = ExceptionDispatchInfo.Capture(e);
-            this.TryInvokeContinuation();
-            return true;
-        }
-    }
-
-    public class ETTaskCompletionSource<T>: ICriticalNotifyCompletion
-    {
-        private AwaiterStatus state;
-        private T value;
-        private ExceptionDispatchInfo exception;
-        private Action continuation; // action or list
-
-        [DebuggerHidden]
-        public ETTask<T> Task => new ETTask<T>(this);
-
-        [DebuggerHidden]
-        public ETTaskCompletionSource<T> GetAwaiter()
-        {
-            return this;
-        }
-
-        [DebuggerHidden]
-        public T GetResult()
-        {
-            switch (this.state)
-            {
-                case AwaiterStatus.Succeeded:
-                    return this.value;
-                case AwaiterStatus.Faulted:
-                    this.exception?.Throw();
-                    this.exception = null;
-                    return default;
-                default:
-                    throw new NotSupportedException("ETask does not allow call GetResult directly when task not completed. Please use 'await'.");
-            }
-        }
-
-        [DebuggerHidden]
-        public bool IsCompleted => state != AwaiterStatus.Pending;
-
-        [DebuggerHidden]
-        public AwaiterStatus Status => state;
-
-        [DebuggerHidden]
-        public void UnsafeOnCompleted(Action action)
-        {
-            this.continuation = action;
-            if (state != AwaiterStatus.Pending)
-            {
-                TryInvokeContinuation();
-            }
-        }
-
-        [DebuggerHidden]
-        public void OnCompleted(Action action)
-        {
-            this.UnsafeOnCompleted(action);
-        }
-
-        [DebuggerHidden]
-        public void SetResult(T result)
-        {
-            if (this.TrySetResult(result))
-            {
-                return;
-            }
-
-            throw new InvalidOperationException("TaskT_TransitionToFinal_AlreadyCompleted");
-        }
-
-        [DebuggerHidden]
-        public void SetException(Exception e)
-        {
-            if (this.TrySetException(e))
-            {
-                return;
-            }
-
-            throw new InvalidOperationException("TaskT_TransitionToFinal_AlreadyCompleted");
-        }
-
-        [DebuggerHidden]
-        private void TryInvokeContinuation()
-        {
-            this.continuation?.Invoke();
-            this.continuation = null;
-        }
-
-        [DebuggerHidden]
-        private bool TrySetResult(T result)
-        {
-            if (this.state != AwaiterStatus.Pending)
-            {
-                return false;
-            }
-
-            this.state = AwaiterStatus.Succeeded;
-
-            this.value = result;
-            this.TryInvokeContinuation();
-            return true;
-        }
-
-        [DebuggerHidden]
-        private bool TrySetException(Exception e)
-        {
-            if (this.state != AwaiterStatus.Pending)
-            {
-                return false;
-            }
-
-            this.state = AwaiterStatus.Faulted;
-
-            this.exception = ExceptionDispatchInfo.Capture(e);
-            this.TryInvokeContinuation();
-            return true;
-        }
-    }
-}

+ 0 - 11
Unity/Assets/Model/Core/Async/ETTaskCompletionSource.cs.meta

@@ -1,11 +0,0 @@
-fileFormatVersion: 2
-guid: 371afc623684c4643ac84af2c4d5aae1
-MonoImporter:
-  externalObjects: {}
-  serializedVersion: 2
-  defaultReferences: []
-  executionOrder: 0
-  icon: {instanceID: 0}
-  userData: 
-  assetBundleName: 
-  assetBundleVariant: 

+ 103 - 28
Unity/Assets/Model/Core/Async/ETTaskHelper.cs

@@ -1,4 +1,5 @@
-using System.Collections.Generic;
+using System;
+using System.Collections.Generic;
 
 namespace ET
 {
@@ -8,7 +9,7 @@ namespace ET
         {
             private int count;
 
-            private List<ETTaskCompletionSource> tcss = new List<ETTaskCompletionSource>();
+            private List<ETTask> tcss = new List<ETTask>();
 
             public CoroutineBlocker(int count)
             {
@@ -25,9 +26,9 @@ namespace ET
 
                 if (this.count == 0)
                 {
-                    List<ETTaskCompletionSource> t = this.tcss;
+                    List<ETTask> t = this.tcss;
                     this.tcss = null;
-                    foreach (ETTaskCompletionSource ttcs in t)
+                    foreach (ETTask ttcs in t)
                     {
                         ttcs.SetResult();
                     }
@@ -35,84 +36,142 @@ namespace ET
                     return;
                 }
 
-                ETTaskCompletionSource tcs = new ETTaskCompletionSource();
+                ETTask tcs = ETTask.Create(true);
+
                 tcss.Add(tcs);
-                await tcs.Task;
+                await tcs;
             }
         }
 
-        public static async ETTask WaitAny<T>(ETTask<T>[] tasks)
+        public static async ETTask<bool> WaitAny<T>(ETTask<T>[] tasks, ETCancellationToken cancellationToken = null)
         {
-            if (tasks == null || tasks.Length == 0)
+            if (tasks.Length == 0)
             {
-                return;
+                return false;
             }
-            
+
             CoroutineBlocker coroutineBlocker = new CoroutineBlocker(2);
+
             foreach (ETTask<T> task in tasks)
             {
                 RunOneTask(task).Coroutine();
             }
 
-            await coroutineBlocker.WaitAsync();
-
             async ETVoid RunOneTask(ETTask<T> task)
             {
                 await task;
                 await coroutineBlocker.WaitAsync();
             }
+
+            await coroutineBlocker.WaitAsync();
+
+            if (cancellationToken == null)
+            {
+                return true;
+            }
+
+            return !cancellationToken.IsCancel();
         }
 
-        public static async ETTask WaitAny(ETTask[] tasks)
+        public static async ETTask<bool> WaitAny(ETTask[] tasks, ETCancellationToken cancellationToken = null)
         {
-            if (tasks == null || tasks.Length == 0)
+            if (tasks.Length == 0)
             {
-                return;
+                return false;
             }
-            
+
             CoroutineBlocker coroutineBlocker = new CoroutineBlocker(2);
+
             foreach (ETTask task in tasks)
             {
                 RunOneTask(task).Coroutine();
             }
 
-            await coroutineBlocker.WaitAsync();
-
             async ETVoid RunOneTask(ETTask task)
             {
                 await task;
                 await coroutineBlocker.WaitAsync();
             }
+
+            await coroutineBlocker.WaitAsync();
+
+            if (cancellationToken == null)
+            {
+                return true;
+            }
+
+            return !cancellationToken.IsCancel();
         }
 
-        public static async ETTask WaitAll<T>(ETTask<T>[] tasks)
+        public static async ETTask<bool> WaitAll<T>(ETTask<T>[] tasks, ETCancellationToken cancellationToken = null)
         {
-            if (tasks == null || tasks.Length == 0)
+            if (tasks.Length == 0)
             {
-                return;
+                return false;
             }
+
             CoroutineBlocker coroutineBlocker = new CoroutineBlocker(tasks.Length + 1);
+
             foreach (ETTask<T> task in tasks)
             {
                 RunOneTask(task).Coroutine();
             }
 
+            async ETVoid RunOneTask(ETTask<T> task)
+            {
+                await task;
+                await coroutineBlocker.WaitAsync();
+            }
+
             await coroutineBlocker.WaitAsync();
 
+            if (cancellationToken == null)
+            {
+                return true;
+            }
+
+            return !cancellationToken.IsCancel();
+        }
+
+        public static async ETTask<bool> WaitAll<T>(List<ETTask<T>> tasks, ETCancellationToken cancellationToken = null)
+        {
+            if (tasks.Count == 0)
+            {
+                return false;
+            }
+
+            CoroutineBlocker coroutineBlocker = new CoroutineBlocker(tasks.Count + 1);
+
+            foreach (ETTask<T> task in tasks)
+            {
+                RunOneTask(task).Coroutine();
+            }
+
             async ETVoid RunOneTask(ETTask<T> task)
             {
                 await task;
                 await coroutineBlocker.WaitAsync();
             }
+
+            await coroutineBlocker.WaitAsync();
+
+            if (cancellationToken == null)
+            {
+                return true;
+            }
+
+            return !cancellationToken.IsCancel();
         }
 
-        public static async ETTask WaitAll(ETTask[] tasks)
+        public static async ETTask<bool> WaitAll(ETTask[] tasks, ETCancellationToken cancellationToken = null)
         {
-            if (tasks == null || tasks.Length == 0)
+            if (tasks.Length == 0)
             {
-                return;
+                return false;
             }
+
             CoroutineBlocker coroutineBlocker = new CoroutineBlocker(tasks.Length + 1);
+
             foreach (ETTask task in tasks)
             {
                 RunOneTask(task).Coroutine();
@@ -125,15 +184,24 @@ namespace ET
                 await task;
                 await coroutineBlocker.WaitAsync();
             }
+
+            if (cancellationToken == null)
+            {
+                return true;
+            }
+
+            return !cancellationToken.IsCancel();
         }
-        
-        public static async ETTask WaitAll(List<ETTask> tasks)
+
+        public static async ETTask<bool> WaitAll(List<ETTask> tasks, ETCancellationToken cancellationToken = null)
         {
-            if (tasks == null || tasks.Count == 0)
+            if (tasks.Count == 0)
             {
-                return;
+                return false;
             }
+
             CoroutineBlocker coroutineBlocker = new CoroutineBlocker(tasks.Count + 1);
+
             foreach (ETTask task in tasks)
             {
                 RunOneTask(task).Coroutine();
@@ -146,6 +214,13 @@ namespace ET
                 await task;
                 await coroutineBlocker.WaitAsync();
             }
+
+            if (cancellationToken == null)
+            {
+                return true;
+            }
+
+            return !cancellationToken.IsCancel();
         }
     }
 }

+ 2 - 0
Unity/Assets/Model/Core/Async/ETVoid.cs

@@ -15,11 +15,13 @@ namespace ET
         [DebuggerHidden]
         public bool IsCompleted => true;
 
+        [MethodImpl(MethodImplOptions.AggressiveInlining)]
         [DebuggerHidden]
         public void OnCompleted(Action continuation)
         {
         }
 
+        [MethodImpl(MethodImplOptions.AggressiveInlining)]
         [DebuggerHidden]
         public void UnsafeOnCompleted(Action continuation)
         {

+ 1 - 1
Unity/Assets/Model/Core/Async/IAwaiter.cs

@@ -1,6 +1,6 @@
 namespace ET
 {
-    public enum AwaiterStatus
+    public enum AwaiterStatus: byte
     {
         /// <summary>The operation has not yet completed.</summary>
         Pending = 0,

+ 5 - 5
Unity/Assets/Model/Core/Entity/TimerComponent.cs

@@ -136,7 +136,7 @@ namespace ET
             {
                 case TimerClass.OnceWaitTimer:
                 {
-                    ETTaskCompletionSource<bool> tcs = timerAction.Callback as ETTaskCompletionSource<bool>;
+                    ETTask<bool> tcs = timerAction.Callback as ETTask<bool>;
                     this.Remove(timerAction.Id);
                     tcs.SetResult(true);
                     break;
@@ -175,7 +175,7 @@ namespace ET
                 return true;
             }
 
-            ETTaskCompletionSource<bool> tcs = new ETTaskCompletionSource<bool>();
+            ETTask<bool> tcs = ETTask<bool>.Create(true);
             TimerAction timer = EntityFactory.CreateWithParent<TimerAction, TimerClass, long, object>(this, TimerClass.OnceWaitTimer, 0, tcs, true);
             this.AddTimer(tillTime, timer);
             long timerId = timer.Id;
@@ -192,7 +192,7 @@ namespace ET
             try
             {
                 cancellationToken?.Add(CancelAction);
-                ret = await tcs.Task;
+                ret = await tcs;
             }
             finally
             {
@@ -214,7 +214,7 @@ namespace ET
             }
             long tillTime = TimeHelper.ServerNow() + time;
 
-            ETTaskCompletionSource<bool> tcs = new ETTaskCompletionSource<bool>();
+            ETTask<bool> tcs = ETTask<bool>.Create(true);
             
             TimerAction timer = EntityFactory.CreateWithParent<TimerAction, TimerClass, long, object>(this, TimerClass.OnceWaitTimer, 0, tcs, true);
             this.AddTimer(tillTime, timer);
@@ -232,7 +232,7 @@ namespace ET
             try
             {
                 cancellationToken?.Add(CancelAction);
-                ret = await tcs.Task;
+                ret = await tcs;
             }
             finally
             {

+ 4 - 4
Unity/Assets/Model/Core/ObjectWait.cs

@@ -51,21 +51,21 @@ namespace ET
 
         public class ResultCallback<K>: IDestroyRun where K : struct, IWaitType
         {
-            private readonly ETTaskCompletionSource<K> tcs;
+            private readonly ETTask<K> tcs;
             private readonly long timer;
 
             public ResultCallback()
             {
-                this.tcs = new ETTaskCompletionSource<K>();
+                this.tcs = ETTask<K>.Create(true);
             }
             
             public ResultCallback(long timer)
             {
                 this.timer = timer;
-                this.tcs = new ETTaskCompletionSource<K>();
+                this.tcs = ETTask<K>.Create(true);
             }
 
-            public ETTask<K> Task => this.tcs.Task;
+            public ETTask<K> Task => this.tcs;
 
             public void SetResult(K k)
             {

+ 8 - 15
Unity/Assets/Model/Core/Options.cs

@@ -1,4 +1,6 @@
 using CommandLine;
+using System;
+using System.Collections.Generic;
 
 namespace ET
 {
@@ -7,28 +9,19 @@ namespace ET
         Game,
         Watcher,
     }
-
+    
     public class Options
     {
-        //[Option("StartConfig", Required = true)]
-        //public string StartConfig { get; set; }
-
         [Option("ServerType", Required = false, Default = ServerType.Game, HelpText = "serverType enum")]
         public ServerType ServerType { get; set; }
 
-        [Option("Develop", Required = false, Default = 0, HelpText = "develop mode, 0正式 1开发 2压测")]
-        public int Develop { get; set; }
-
         [Option("Process", Required = false, Default = 1)]
-        public int Process { get; set; }
-
-        [Option("CreateScenes", Required = false, Default = 1)]
-        public int CreateScenes { get; set; }
-
-        [Option("Console", Required = false, Default = 0)]
-        public int Console { get; set; }
+        public int Process { get; set; } = 1;
+        
+        [Option("Develop", Required = false, Default = 0, HelpText = "develop mode, 0正式 1开发 2压测")]
+        public int Develop { get; set; } = 0;
 
         [Option("LogLevel", Required = false, Default = 0)]
-        public int LogLevel { get; set; }
+        public int LogLevel { get; set; } = 2;
     }
 }

+ 1 - 1
Unity/Assets/Model/Core/Options.cs.meta

@@ -1,5 +1,5 @@
 fileFormatVersion: 2
-guid: b14bd528d21af4a7ba57e07b2de5f77a
+guid: fc33d5decd83d413d85fc266d8490cb4
 MonoImporter:
   externalObjects: {}
   serializedVersion: 2

+ 13 - 21
Unity/Assets/Model/Module/CoroutineLock/CoroutineLock.cs

@@ -1,33 +1,25 @@
-namespace ET
+using System;
+
+namespace ET
 {
-    public class CoroutineLockSystem : AwakeSystem<CoroutineLock, CoroutineLockType, long>
+    public readonly struct CoroutineLock: IDisposable
     {
-        public override void Awake(CoroutineLock self, CoroutineLockType coroutineLockType, long key)
-        {
-            self.Awake(coroutineLockType, key);
-        }
-    }  
+        private readonly CoroutineLockComponent coroutineLockComponent;
+        private readonly CoroutineLockType coroutineLockType;
+        private readonly long key;
+        private readonly short index;
 
-    public class CoroutineLock: Entity
-    {
-        private CoroutineLockType coroutineLockType;
-        private long key;
-        
-        public void Awake(CoroutineLockType type, long k)
+        public CoroutineLock(CoroutineLockComponent coroutineLockComponent, CoroutineLockType type, long k, short index)
         {
+            this.coroutineLockComponent = coroutineLockComponent;
             this.coroutineLockType = type;
             this.key = k;
+            this.index = index;
         }
 
-        public override void Dispose()
+        public void Dispose()
         {
-            if (this.IsDisposed)
-            {
-                return;
-            }
-            base.Dispose();
-            
-            CoroutineLockComponent.Instance.Notify(coroutineLockType, this.key);
+            coroutineLockComponent.Notify(coroutineLockType, this.key, this.index);
         }
     }
 }

+ 201 - 23
Unity/Assets/Model/Module/CoroutineLock/CoroutineLockComponent.cs

@@ -1,31 +1,170 @@
 using System;
 using System.Collections.Generic;
+using System.Linq;
 
 namespace ET
 {
+    using CoroutineLockQueue = SortedDictionary<int, ETTask<CoroutineLock>>;
+    using CoroutineLockQueueType = Dictionary<long, SortedDictionary<int, ETTask<CoroutineLock>>>;
     
-    public class CoroutineLockComponentSystem : AwakeSystem<CoroutineLockComponent>
+    public struct CoroutineLockTimer
+    {
+        public CoroutineLockType CoroutineLockType;
+        public long Key;
+        public int N;
+        
+        public CoroutineLockTimer(CoroutineLockType coroutineLockType, long key, int n)
+        {
+            this.CoroutineLockType = coroutineLockType;
+            this.Key = key;
+            this.N = n;
+        }
+    }
+    
+    [ObjectSystem]
+    public class CoroutineLockComponentSystem: AwakeSystem<CoroutineLockComponent>
     {
         public override void Awake(CoroutineLockComponent self)
         {
             self.Awake();
         }
     }
-    
+
+    public class CoroutineLockComponentUpdateSystem: UpdateSystem<CoroutineLockComponent>
+    {
+        public override void Update(CoroutineLockComponent self)
+        {
+            self.Update();
+        }
+    }
+
     public class CoroutineLockComponent: Entity
     {
-        public static CoroutineLockComponent Instance { get; private set; }
+        public static CoroutineLockComponent Instance
+        {
+            get;
+            private set;
+        }
+
+        private int n;
+        
+        private readonly Queue<CoroutineLockQueue> coroutineLockQueuePool = new Queue<CoroutineLockQueue>();
+
+        private CoroutineLockQueue FetchCoroutineLockQueue()
+        {
+            if (this.coroutineLockQueuePool.Count == 0)
+            {
+                return new CoroutineLockQueue();
+            }
+
+            return this.coroutineLockQueuePool.Dequeue();
+        }
+        
+        private void RecycleCoroutineLockQueue(CoroutineLockQueue coroutineLockQueue)
+        {
+            this.coroutineLockQueuePool.Enqueue(coroutineLockQueue);
+        }
+
+        private readonly List<CoroutineLockQueueType> list = new List<CoroutineLockQueueType>((int) CoroutineLockType.Max);
+
+        private readonly Queue<(CoroutineLockType, long)> nextFrameRun = new Queue<(CoroutineLockType, long)>();
+
+        private readonly MultiMap<long, CoroutineLockTimer> timers = new MultiMap<long, CoroutineLockTimer>();
+        
+        private readonly Queue<long> timeOutIds = new Queue<long>();
+
+        private readonly Queue<CoroutineLockTimer> timerOutTimer = new Queue<CoroutineLockTimer>();
 
-        private readonly List<CoroutineLockQueueType> list = new List<CoroutineLockQueueType>((int)CoroutineLockType.Max);
+        private long minTime;
 
         public void Awake()
         {
             Instance = this;
             for (int i = 0; i < this.list.Capacity; ++i)
             {
-                CoroutineLockQueueType coroutineLockQueueType = EntityFactory.Create<CoroutineLockQueueType>(this.Domain);
-                this.list.Add(coroutineLockQueueType);
-                coroutineLockQueueType.Parent = this;
+                this.list.Add(new CoroutineLockQueueType());
+            }
+        }
+
+        public void Update()
+        {
+            int count = this.nextFrameRun.Count;
+            // 注意这里不能将this.nextFrameRun.Count 放到for循环中,因为循环过程中会有对象继续加入队列
+            for (int i = 0; i < count; ++i)
+            {
+                (CoroutineLockType coroutineLockType, long key) = this.nextFrameRun.Dequeue();
+                this.Notify(coroutineLockType, key, 1);
+            }
+
+            TimeoutCheck();
+        }
+
+        // 这里没有用TimerComponent,是为了避免每个计时器一个回调的gc
+        private void TimeoutCheck()
+        {
+            // 超时的锁
+            if (this.timers.Count == 0)
+            {
+                return;
+            }
+
+            long timeNow = TimeHelper.ClientFrameTime();
+
+            if (timeNow < this.minTime)
+            {
+                return;
+            }
+
+            foreach (KeyValuePair<long, List<CoroutineLockTimer>> kv in this.timers)
+            {
+                long k = kv.Key;
+                if (k > timeNow)
+                {
+                    minTime = k;
+                    break;
+                }
+
+                this.timeOutIds.Enqueue(k);
+            }
+            
+            this.timerOutTimer.Clear();
+            
+            while (this.timeOutIds.Count > 0)
+            {
+                long time = this.timeOutIds.Dequeue();
+                foreach (CoroutineLockTimer coroutineLockTimer in this.timers[time])
+                {
+                    this.timerOutTimer.Enqueue(coroutineLockTimer);
+                }
+                this.timers.Remove(time);
+            }
+            
+            while (this.timerOutTimer.Count > 0)
+            {
+                CoroutineLockTimer coroutineLockTimer = this.timerOutTimer.Dequeue();
+
+                CoroutineLockQueueType coroutineLockQueueType = this.list[(int) coroutineLockTimer.CoroutineLockType];
+                if (!coroutineLockQueueType.TryGetValue(coroutineLockTimer.Key, out CoroutineLockQueue queue))
+                {
+                    continue;
+                }
+                if (!queue.TryGetValue(coroutineLockTimer.N, out ETTask<CoroutineLock> tcs))
+                {
+                    continue;
+                }
+                
+                queue.Remove(coroutineLockTimer.N);
+                
+                if (queue.Count == 0)
+                {
+                    this.RecycleCoroutineLockQueue(queue);
+                    coroutineLockQueueType.Remove(coroutineLockTimer.Key);
+                }
+                
+                CoroutineLockType coroutineLockType = coroutineLockTimer.CoroutineLockType;
+                long key = coroutineLockTimer.Key;
+                
+                tcs.SetException(new Exception($"coroutineLock timeout maybe have deadlock: {coroutineLockType} {key}"));
             }
         }
 
@@ -35,44 +174,83 @@ namespace ET
             {
                 return;
             }
-            
+
             base.Dispose();
-            
+
             this.list.Clear();
         }
 
-        public async ETTask<CoroutineLock> Wait(CoroutineLockType coroutineLockType, long key)
+        public async ETTask<CoroutineLock> Wait(CoroutineLockType coroutineLockType, long key, int time = 60000)
         {
             CoroutineLockQueueType coroutineLockQueueType = this.list[(int) coroutineLockType];
             if (!coroutineLockQueueType.TryGetValue(key, out CoroutineLockQueue queue))
             {
-                queue = EntityFactory.Create<CoroutineLockQueue>(this.Domain);
-                coroutineLockQueueType.Add(key, queue);
-                
-                return EntityFactory.CreateWithParent<CoroutineLock, CoroutineLockType, long>(this, coroutineLockType, key);
+                coroutineLockQueueType.Add(key, FetchCoroutineLockQueue());
+
+                return new CoroutineLock(this, coroutineLockType, key, 1);
             }
+
+            ETTask<CoroutineLock> tcs = ETTask<CoroutineLock>.Create(true);
             
-            ETTaskCompletionSource<CoroutineLock> tcs = new ETTaskCompletionSource<CoroutineLock>();
-            queue.Enqueue(tcs);
-            return await tcs.Task;
+            int i = ++this.n;
+            if (time > 0)
+            {
+                long tillTime = TimeHelper.ClientFrameTime() + time;
+                CoroutineLockTimer coroutineLockTimer = new CoroutineLockTimer(coroutineLockType, key, i);
+                this.timers.Add(tillTime, coroutineLockTimer);
+                if (tillTime < this.minTime)
+                {
+                    this.minTime = tillTime;
+                }
+            }
+            queue.Add(i, tcs);
+            return await tcs;
         }
-        
-        public void Notify(CoroutineLockType coroutineLockType, long key)
+
+        public int GetCount(CoroutineLockType coroutineLockType, long key)
         {
             CoroutineLockQueueType coroutineLockQueueType = this.list[(int) coroutineLockType];
             if (!coroutineLockQueueType.TryGetValue(key, out CoroutineLockQueue queue))
             {
-                throw new Exception($"first work notify not find queue");
+                return 0;
             }
+
+            return queue.Count;
+        }
+
+        public void Notify(CoroutineLockType coroutineLockType, long key, short index)
+        {
+            if (this.list.Count == 0) // 客户端关闭了
+            {
+                return;
+            }
+            CoroutineLockQueueType coroutineLockQueueType = this.list[(int) coroutineLockType];
+            if (!coroutineLockQueueType.TryGetValue(key, out CoroutineLockQueue queue))
+            {
+                return;
+                // coroutineLockQueueType是空的也正常,因为有些协程锁可能超时删除了
+                //throw new Exception($"first work notify not find queue");
+            }
+
             if (queue.Count == 0)
             {
+                this.RecycleCoroutineLockQueue(queue);
                 coroutineLockQueueType.Remove(key);
-                queue.Dispose();
+                return;
+            }
+            
+            // 注意因为协程锁Dispose会调用下一个协程,如果队列过多,堆栈可能溢出,所以这里限制了一次最多递归10层,
+            // 超出则记录一下,下一帧再继续
+            if (index > 10)
+            {
+                this.nextFrameRun.Enqueue((coroutineLockType, key));
                 return;
             }
 
-            ETTaskCompletionSource<CoroutineLock> tcs = queue.Dequeue();
-            tcs.SetResult(EntityFactory.CreateWithParent<CoroutineLock, CoroutineLockType, long>(this, coroutineLockType, key));
+            var kv = queue.First();
+            var tcs = kv.Value;
+            queue.Remove(kv.Key);
+            tcs.SetResult(new CoroutineLock(this, coroutineLockType, key, (short)(index + 1)));
         }
     }
 }

+ 0 - 39
Unity/Assets/Model/Module/CoroutineLock/CoroutineLockQueue.cs

@@ -1,39 +0,0 @@
-using System.Collections.Generic;
-
-namespace ET
-{
-    public class CoroutineLockQueue: Entity
-    {
-        private readonly Queue<ETTaskCompletionSource<CoroutineLock>> queue = new Queue<ETTaskCompletionSource<CoroutineLock>>();
-
-        public void Enqueue(ETTaskCompletionSource<CoroutineLock> tcs)
-        {
-            this.queue.Enqueue(tcs);
-        }
-
-        public ETTaskCompletionSource<CoroutineLock> Dequeue()
-        {
-            return this.queue.Dequeue();
-        }
-
-        public int Count
-        {
-            get
-            {
-                return this.queue.Count;
-            }
-        }
-
-        public override void Dispose()
-        {
-            if (this.IsDisposed)
-            {
-                return;
-            }
-            
-            base.Dispose();
-            
-            this.queue.Clear();
-        }
-    }
-}

+ 0 - 11
Unity/Assets/Model/Module/CoroutineLock/CoroutineLockQueue.cs.meta

@@ -1,11 +0,0 @@
-fileFormatVersion: 2
-guid: c28746c1043317e4fb04dcd7409edac6
-MonoImporter:
-  externalObjects: {}
-  serializedVersion: 2
-  defaultReferences: []
-  executionOrder: 0
-  icon: {instanceID: 0}
-  userData: 
-  assetBundleName: 
-  assetBundleVariant: 

+ 0 - 36
Unity/Assets/Model/Module/CoroutineLock/CoroutineLockQueueType.cs

@@ -1,36 +0,0 @@
-using System.Collections.Generic;
-
-namespace ET
-{
-    public class CoroutineLockQueueType: Entity
-    {
-        private readonly Dictionary<long, CoroutineLockQueue> workQueues = new Dictionary<long, CoroutineLockQueue>();
-
-        public void Add(long key, CoroutineLockQueue coroutineLockQueue)
-        {
-            this.workQueues.Add(key, coroutineLockQueue);
-            coroutineLockQueue.Parent = this;
-        }
-
-        public void Remove(long key)
-        {
-            if (!this.workQueues.TryGetValue(key, out CoroutineLockQueue queue))
-            {
-                return;
-            }
-
-            this.workQueues.Remove(key);
-            queue.Dispose();
-        }
-
-        public bool ContainsKey(long key)
-        {
-            return this.workQueues.ContainsKey(key);
-        }
-
-        public bool TryGetValue(long key, out CoroutineLockQueue coroutineLockQueue)
-        {
-            return this.workQueues.TryGetValue(key, out coroutineLockQueue);
-        }
-    }
-}

+ 0 - 11
Unity/Assets/Model/Module/CoroutineLock/CoroutineLockQueueType.cs.meta

@@ -1,11 +0,0 @@
-fileFormatVersion: 2
-guid: ea05742688afd7b4fac282e0a74ba844
-MonoImporter:
-  externalObjects: {}
-  serializedVersion: 2
-  defaultReferences: []
-  executionOrder: 0
-  icon: {instanceID: 0}
-  userData: 
-  assetBundleName: 
-  assetBundleVariant: 

+ 3 - 12
Unity/Assets/Model/Module/CoroutineLock/CoroutineLockType.cs

@@ -1,4 +1,4 @@
-namespace ET
+namespace ET
 {
     public enum CoroutineLockType
     {
@@ -6,18 +6,9 @@
         Location, // location进程上使用
         ActorLocationSender, // ActorLocationSender中队列消息 
         Mailbox, // Mailbox中队列
-        AccountName, // Realm上验证账号时使用
-        AccountId, // Gate上登陆账号时使用
-        UnitId,  // Map服务器上线下线时使用
-        SendMail, // 发送Mail时使用
         DB, // 存储数据库
-        LevelSeal,//玩家请求是否达到等级封印时使用
-        ClientChangeScene, // 客户端切换场景
-        
-        // Client
         Resources,
-        ResourcesLoader,
-        
-        Max, // 这个必须在最后
+        //必须放最后
+        Max,
     }
 }

+ 4 - 4
Unity/Assets/Model/Module/Message/Session.cs

@@ -20,12 +20,12 @@ namespace ET
         private readonly struct RpcInfo
         {
             public readonly IRequest Request;
-            public readonly ETTaskCompletionSource<IResponse> Tcs;
+            public readonly ETTask<IResponse> Tcs;
 
             public RpcInfo(IRequest request)
             {
                 this.Request = request;
-                this.Tcs = new ETTaskCompletionSource<IResponse>();
+                this.Tcs = ETTask<IResponse>.Create(true);
             }
         }
 
@@ -144,7 +144,7 @@ namespace ET
             try
             {
                 cancellationToken?.Add(CancelAction);
-                ret = await rpcInfo.Tcs.Task;
+                ret = await rpcInfo.Tcs;
             }
             finally
             {
@@ -160,7 +160,7 @@ namespace ET
             this.requestCallbacks[rpcId] = rpcInfo;
             request.RpcId = rpcId;
             this.Send(request);
-            return await rpcInfo.Tcs.Task;
+            return await rpcInfo.Tcs;
         }
 
         public void Reply(IResponse message)

+ 1 - 1
Unity/Assets/Model/Module/Network/KChannel.cs

@@ -1,4 +1,4 @@
-using System;
+using System;
 using System.Collections.Concurrent;
 using System.Collections.Generic;
 using System.IO;

+ 2 - 2
Unity/Assets/Model/Module/Resource/ResourcesComponent.cs

@@ -63,7 +63,7 @@ namespace ET
     {
         public static async ETTask<AssetBundle> UnityLoadBundleAsync(string path)
         {
-            var tcs = new ETTaskCompletionSource<AssetBundle>();
+            var tcs = ETTask<AssetBundle>.Create(true);
             AssetBundleCreateRequest request = AssetBundle.LoadFromFileAsync(path);
             request.completed += operation => { tcs.SetResult(request.assetBundle); };
             return await tcs;
@@ -71,7 +71,7 @@ namespace ET
 
         public static async ETTask<UnityEngine.Object[]> UnityLoadAssetAsync(AssetBundle assetBundle)
         {
-            var tcs = new ETTaskCompletionSource<UnityEngine.Object[]>();
+            var tcs = ETTask<UnityEngine.Object[]>.Create(true);
             AssetBundleRequest request = assetBundle.LoadAllAssetsAsync();
             request.completed += operation => { tcs.SetResult(request.allAssets); };
             return await tcs;

+ 3 - 3
Unity/Assets/Model/Module/UnityWebRequest/UnityWebRequestAsync.cs

@@ -28,7 +28,7 @@ namespace ET
 
 		public bool isCancel;
 
-		public ETTaskCompletionSource tcs;
+		public ETTask tcs;
 		
 		public override void Dispose()
 		{
@@ -91,14 +91,14 @@ namespace ET
 
 		public async ETTask DownloadAsync(string url)
 		{
-			this.tcs = new ETTaskCompletionSource();
+			this.tcs = ETTask.Create(true);
 			
 			url = url.Replace(" ", "%20");
 			this.Request = UnityWebRequest.Get(url);
 			this.Request.certificateHandler = certificateHandler;
 			this.Request.SendWebRequest();
 			
-			await this.tcs.Task;
+			await this.tcs;
 		}
 	}
 }

+ 55 - 18
Unity/Assets/Model/Module/UnityWebRequest/UnityWebRequestRenewalAsync.cs

@@ -33,7 +33,7 @@ namespace ET
 
         public bool isCancel;
 
-        public ETTaskCompletionSource tcs;
+        public ETTask tcs;
 
         //请求资源类型
         private class RequestType
@@ -76,17 +76,24 @@ namespace ET
             get
             {
                 foreach (UnityWebRequest webRequest in this.dataRequests)
+                {
                     if (!string.IsNullOrEmpty(webRequest.error))
+                    {
                         return webRequest.error;
+                    }
+                }
+
                 return "";
             }
         }
 
         //批量开启任务下载
-        void DownloadPackages()
+        private void DownloadPackages()
         {
             if (dataRequests.Count >= maxCount || this.downloadIndex == totalBytes - 1)
+            {
                 return;
+            }
 
             //开启一个下载任务
             void DownloadPackage(long start, long end)
@@ -104,17 +111,22 @@ namespace ET
             for (int i = dataRequests.Count; i < maxCount; i++)
             {
                 long start = this.byteWrites + i * packageLength;
-                long end   = this.byteWrites + (i + 1) * packageLength - 1;
+                long end = this.byteWrites + (i + 1) * packageLength - 1;
                 if (end > this.totalBytes)
+                {
                     end = this.totalBytes - 1;
+                }
+
                 DownloadPackage(start, end);
                 if (end == this.totalBytes - 1)
+                {
                     break;
+                }
             }
         }
 
         //一次批量下载完成后写文件
-        void WritePackages()
+        private void WritePackages()
         {
             //写入单个包
             void WritePackage(UnityWebRequest webRequest)
@@ -140,7 +152,7 @@ namespace ET
         }
 
         //更新文件体下载
-        void UpdatePackages()
+        private void UpdatePackages()
         {
             if (this.isCancel)
             {
@@ -156,13 +168,17 @@ namespace ET
 
             this.WritePackages();
             if (this.byteWrites == this.totalBytes)
+            {
                 this.tcs.SetResult();
+            }
             else
+            {
                 this.DownloadPackages();
+            }
         }
 
         //更新文件头下载
-        void UpdateHead()
+        private void UpdateHead()
         {
             if (this.isCancel)
             {
@@ -183,14 +199,17 @@ namespace ET
 
             this.tcs.SetResult();
         }
-        
+
         //检测是不是同一个文件
-        bool CheckSameFile(string modifiedTime)
+        private bool CheckSameFile(string modifiedTime)
         {
             string cacheValue = PlayerPrefs.GetString(Url);
-            string currentValue = this.totalBytes+"|"+modifiedTime;
+            string currentValue = this.totalBytes + "|" + modifiedTime;
             if (cacheValue == currentValue)
+            {
                 return true;
+            }
+
             PlayerPrefs.SetString(Url, currentValue);
             PlayerPrefs.Save();
             Log.Debug($"断点续传下载一个新的文件:{Url} cacheValue:{cacheValue} currentValue:{currentValue}");
@@ -209,10 +228,10 @@ namespace ET
         {
             try
             {
-                url                = url.Replace(" ", "%20");
-                this.Url           = url;
+                url = url.Replace(" ", "%20");
+                this.Url = url;
                 this.packageLength = packageLength;
-                this.maxCount      = maxCount;
+                this.maxCount = maxCount;
                 Log.Debug("Web Request:" + url);
 
                 #region Download File Header
@@ -220,10 +239,10 @@ namespace ET
                 this.requestType = RequestType.Head;
                 //下载文件头
                 Log.Debug($"Request Head: {Url}");
-                this.tcs         = new ETTaskCompletionSource();
+                this.tcs = ETTask.Create(true);
                 this.headRequest = UnityWebRequest.Head(Url);
                 this.headRequest.SendWebRequest();
-                await this.tcs.Task;
+                await this.tcs;
                 this.totalBytes = long.Parse(this.headRequest.GetResponseHeader("Content-Length"));
                 string modifiedTime = this.headRequest.GetResponseHeader("Last-Modified");
                 Log.Debug($"totalBytes: {this.totalBytes}");
@@ -233,13 +252,17 @@ namespace ET
                 #endregion
 
                 #region Check Local File
+
                 //打开或创建
                 fileStream = new FileStream(filePath, FileMode.OpenOrCreate, FileAccess.Write);
                 //获取已下载长度
                 this.byteWrites = fileStream.Length;
                 //通过本地缓存的服务器文件修改时间和文件总长度检测服务器是否是同一个文件 不是同一个从头开始写入
                 if (!CheckSameFile(modifiedTime))
+                {
                     this.byteWrites = 0;
+                }
+
                 Log.Debug($"byteWrites: {this.byteWrites}");
                 if (this.byteWrites == this.totalBytes)
                 {
@@ -257,9 +280,9 @@ namespace ET
                 //下载文件数据
                 requestType = RequestType.Data;
                 Log.Debug($"Request Data: {Url}");
-                this.tcs = new ETTaskCompletionSource();
+                this.tcs = ETTask.Create(true);
                 this.DownloadPackages();
-                await this.tcs.Task;
+                await this.tcs;
 
                 #endregion
             }
@@ -276,7 +299,10 @@ namespace ET
             get
             {
                 if (this.totalBytes == 0)
+                {
                     return 0;
+                }
+
                 return (float) ((this.byteWrites + ByteDownloaded) / (double) this.totalBytes);
             }
         }
@@ -288,7 +314,10 @@ namespace ET
             {
                 long length = 0;
                 foreach (UnityWebRequest dataRequest in this.dataRequests)
+                {
                     length += dataRequest.downloadHandler.data.Length;
+                }
+
                 return length;
             }
         }
@@ -296,9 +325,14 @@ namespace ET
         public void Update()
         {
             if (this.requestType == RequestType.Head)
+            {
                 this.UpdateHead();
+            }
+
             if (this.requestType == RequestType.Data)
+            {
                 this.UpdatePackages();
+            }
         }
 
         public override void Dispose()
@@ -312,12 +346,15 @@ namespace ET
             headRequest?.Dispose();
             headRequest = null;
             foreach (UnityWebRequest dataRequest in this.dataRequests)
+            {
                 dataRequest.Dispose();
+            }
+
             dataRequests.Clear();
             this.fileStream?.Close();
             this.fileStream?.Dispose();
             this.fileStream = null;
-            this.isCancel   = false;
+            this.isCancel = false;
         }
     }
-}
+}

+ 1 - 1
Unity/Assets/ModelView/Scene/SceneChangeComponent.cs

@@ -5,6 +5,6 @@ namespace ET
     public class SceneChangeComponent: Entity
     {
         public AsyncOperation loadMapOperation;
-        public ETTaskCompletionSource tcs;
+        public ETTask tcs;
     }
 }