You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
313 lines
8.4 KiB
313 lines
8.4 KiB
using System; |
|
using System.Collections.Generic; |
|
using System.Diagnostics; |
|
using System.Runtime.CompilerServices; |
|
using System.Runtime.ExceptionServices; |
|
|
|
namespace ET |
|
{ |
|
[AsyncMethodBuilder(typeof (ETAsyncTaskMethodBuilder))] |
|
public class ETTask: ICriticalNotifyCompletion |
|
{ |
|
public static Action<Exception> ExceptionHandler; |
|
|
|
public static ETTaskCompleted CompletedTask |
|
{ |
|
get |
|
{ |
|
return new ETTaskCompleted(); |
|
} |
|
} |
|
|
|
private static readonly Queue<ETTask> queue = new Queue<ETTask>(); |
|
|
|
/// <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() |
|
{ |
|
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() |
|
{ |
|
} |
|
|
|
[DebuggerHidden] |
|
private async ETVoid InnerCoroutine() |
|
{ |
|
await this; |
|
} |
|
|
|
[DebuggerHidden] |
|
public void Coroutine() |
|
{ |
|
InnerCoroutine().Coroutine(); |
|
} |
|
|
|
[DebuggerHidden] |
|
public ETTask GetAwaiter() |
|
{ |
|
return this; |
|
} |
|
|
|
|
|
public bool IsCompleted |
|
{ |
|
[DebuggerHidden] |
|
get |
|
{ |
|
return this.state != AwaiterStatus.Pending; |
|
} |
|
} |
|
|
|
[DebuggerHidden] |
|
public void UnsafeOnCompleted(Action action) |
|
{ |
|
if (this.state != AwaiterStatus.Pending) |
|
{ |
|
action?.Invoke(); |
|
return; |
|
} |
|
|
|
this.callback = action; |
|
} |
|
|
|
[DebuggerHidden] |
|
public void OnCompleted(Action action) |
|
{ |
|
this.UnsafeOnCompleted(action); |
|
} |
|
|
|
[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; |
|
this.Recycle(); |
|
c?.Throw(); |
|
break; |
|
default: |
|
throw new NotSupportedException("ETTask does not allow call GetResult directly when task not completed. Please use 'await'."); |
|
} |
|
} |
|
|
|
[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 class ETTask<T>: ICriticalNotifyCompletion |
|
{ |
|
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(); |
|
} |
|
} |
|
|
|
private bool fromPool; |
|
private AwaiterStatus state; |
|
private T value; |
|
private object callback; // Action or ExceptionDispatchInfo |
|
|
|
private ETTask() |
|
{ |
|
} |
|
|
|
[DebuggerHidden] |
|
private async ETVoid InnerCoroutine() |
|
{ |
|
await this; |
|
} |
|
|
|
[DebuggerHidden] |
|
public void Coroutine() |
|
{ |
|
InnerCoroutine().Coroutine(); |
|
} |
|
|
|
[DebuggerHidden] |
|
public ETTask<T> GetAwaiter() |
|
{ |
|
return this; |
|
} |
|
|
|
[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; |
|
this.Recycle(); |
|
c?.Throw(); |
|
return default; |
|
default: |
|
throw new NotSupportedException("ETask does not allow call GetResult directly when task not completed. Please use 'await'."); |
|
} |
|
} |
|
|
|
|
|
public bool IsCompleted |
|
{ |
|
[DebuggerHidden] |
|
get |
|
{ |
|
return state != AwaiterStatus.Pending; |
|
} |
|
} |
|
|
|
[DebuggerHidden] |
|
public void UnsafeOnCompleted(Action action) |
|
{ |
|
if (this.state != AwaiterStatus.Pending) |
|
{ |
|
action?.Invoke(); |
|
return; |
|
} |
|
|
|
this.callback = action; |
|
} |
|
|
|
[DebuggerHidden] |
|
public void OnCompleted(Action action) |
|
{ |
|
this.UnsafeOnCompleted(action); |
|
} |
|
|
|
[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(); |
|
} |
|
|
|
[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(); |
|
} |
|
} |
|
} |