From 6be955816b8a8ca09280a5faa720eee541e93741 Mon Sep 17 00:00:00 2001 From: neuecc Date: Thu, 7 May 2020 07:18:51 +0900 Subject: [PATCH] Improve AsyncTrigger performance --- .../UniTask/Triggers/AsyncTriggerBase.cs | 169 ++++++++++-------- src/UniTask/Assets/Scenes/SandboxMain.cs | 18 +- 2 files changed, 110 insertions(+), 77 deletions(-) diff --git a/src/UniTask/Assets/Plugins/UniTask/Triggers/AsyncTriggerBase.cs b/src/UniTask/Assets/Plugins/UniTask/Triggers/AsyncTriggerBase.cs index a3415a8..8568d03 100644 --- a/src/UniTask/Assets/Plugins/UniTask/Triggers/AsyncTriggerBase.cs +++ b/src/UniTask/Assets/Plugins/UniTask/Triggers/AsyncTriggerBase.cs @@ -212,11 +212,16 @@ namespace Cysharp.Threading.Tasks.Triggers // optimize: many cases, handler is single. AsyncTriggerHandler singleHandler; - List> handlers; + AsyncTriggerHandler[] handlers; + + // when running(in TrySetResult), does not add immediately. + bool isRunning; + AsyncTriggerHandler waitHandler; + MinimumQueue> waitQueue; public bool TrySetResult(T value) { - List exceptions = null; + isRunning = true; if (singleHandler != null) { @@ -226,56 +231,44 @@ namespace Cysharp.Threading.Tasks.Triggers } catch (Exception ex) { - if (handlers == null) - { - throw; - } - else - { - exceptions = new List(); - exceptions.Add(ex); - } + Debug.LogException(ex); } } if (handlers != null) { - // make snapshot - var rentArray = ArrayPoolUtil.CopyToRentArray(handlers); - var clearArray = true; - try + for (int i = 0; i < handlers.Length; i++) { - var array = rentArray.Array; - var len = rentArray.Length; - for (int i = 0; i < len; i++) + if (handlers[i] != null) { try { - ((IResolvePromise)array[i]).TrySetResult(value); + ((IResolvePromise)handlers[i]).TrySetResult(value); } catch (Exception ex) { - if (exceptions == null) - { - exceptions = new List(); - } - exceptions.Add(ex); - } - finally - { - array[i] = null; + handlers[i] = null; + Debug.LogException(ex); } } } - finally - { - rentArray.DisposeManually(clearArray); - } } - if (exceptions != null) + isRunning = false; + + if (waitHandler != null) { - throw new AggregateException(exceptions); + var h = waitHandler; + waitHandler = null; + Add(h); + } + + if (waitQueue != null) + { + while (waitQueue.Count != 0) + { + Add(waitQueue.Dequeue()); + } } return true; @@ -283,7 +276,7 @@ namespace Cysharp.Threading.Tasks.Triggers public bool TrySetCanceled(CancellationToken cancellationToken) { - List exceptions = null; + isRunning = true; if (singleHandler != null) { @@ -293,56 +286,44 @@ namespace Cysharp.Threading.Tasks.Triggers } catch (Exception ex) { - if (handlers == null) - { - throw; - } - else - { - exceptions = new List(); - exceptions.Add(ex); - } + Debug.LogException(ex); } } if (handlers != null) { - // make snapshot - var rentArray = ArrayPoolUtil.CopyToRentArray(handlers); - var clearArray = true; - try + for (int i = 0; i < handlers.Length; i++) { - var array = rentArray.Array; - var len = rentArray.Length; - for (int i = 0; i < len; i++) + if (handlers[i] != null) { try { - ((ICancelPromise)array[i]).TrySetCanceled(cancellationToken); + ((ICancelPromise)handlers[i]).TrySetCanceled(cancellationToken); } catch (Exception ex) { - if (exceptions == null) - { - exceptions = new List(); - } - exceptions.Add(ex); - } - finally - { - array[i] = null; + Debug.LogException(ex); + handlers[i] = null; } } } - finally - { - rentArray.DisposeManually(clearArray); - } } - if (exceptions != null) + isRunning = false; + + if (waitHandler != null) { - throw new AggregateException(exceptions); + var h = waitHandler; + waitHandler = null; + Add(h); + } + + if (waitQueue != null) + { + while (waitQueue.Count != 0) + { + Add(waitQueue.Dequeue()); + } } return true; @@ -350,6 +331,22 @@ namespace Cysharp.Threading.Tasks.Triggers public void Add(AsyncTriggerHandler handler) { + if (isRunning) + { + if (waitHandler == null) + { + waitHandler = handler; + return; + } + + if (waitQueue == null) + { + waitQueue = new MinimumQueue>(4); + } + waitQueue.Enqueue(handler); + return; + } + if (singleHandler == null) { singleHandler = handler; @@ -358,12 +355,36 @@ namespace Cysharp.Threading.Tasks.Triggers { if (handlers == null) { - handlers = new List>(); + handlers = new AsyncTriggerHandler[4]; + } + + // check empty + for (int i = 0; i < handlers.Length; i++) + { + if (handlers[i] == null) + { + handlers[i] = handler; + return; + } + } + + // full, ensure capacity + var last = handlers.Length; + { + EnsureCapacity(ref handlers); + handlers[last] = handler; } - handlers.Add(handler); } } + static void EnsureCapacity(ref AsyncTriggerHandler[] array) + { + var newSize = array.Length * 2; + var newArray = new AsyncTriggerHandler[newSize]; + Array.Copy(array, 0, newArray, 0, array.Length); + array = newArray; + } + public void Remove(AsyncTriggerHandler handler) { if (singleHandler == handler) @@ -374,7 +395,15 @@ namespace Cysharp.Threading.Tasks.Triggers { if (handlers != null) { - handlers.Remove(handler); + for (int i = 0; i < handlers.Length; i++) + { + if (handlers[i] == handler) + { + // fill null. + handlers[i] = null; + return; + } + } } } } diff --git a/src/UniTask/Assets/Scenes/SandboxMain.cs b/src/UniTask/Assets/Scenes/SandboxMain.cs index b7fcafb..43a79c9 100644 --- a/src/UniTask/Assets/Scenes/SandboxMain.cs +++ b/src/UniTask/Assets/Scenes/SandboxMain.cs @@ -124,9 +124,11 @@ public class SandboxMain : MonoBehaviour CancellationTokenSource cts = new CancellationTokenSource(); var trigger = this.GetAsyncUpdateTrigger(); - Go(trigger, cts.Token).Forget(); - //Go(trigger).Forget(); - //Go(trigger).Forget(); + Go(trigger, 1, cts.Token).Forget(); + Go(trigger, 2, cts.Token).Forget(); + Go(trigger, 3, cts.Token).Forget(); + Go(trigger, 4, cts.Token).Forget(); + Go(trigger, 5, cts.Token).Forget(); Application.logMessageReceived += Application_logMessageReceived; @@ -141,7 +143,7 @@ public class SandboxMain : MonoBehaviour okButton.onClick.AddListener(() => { - FooAsync().Forget(); + // FooAsync().Forget(); }); cancelButton.onClick.AddListener(() => @@ -154,7 +156,7 @@ public class SandboxMain : MonoBehaviour }); } - async UniTaskVoid Go(AsyncUpdateTrigger trigger, CancellationToken ct) + async UniTaskVoid Go(AsyncUpdateTrigger trigger, int i, CancellationToken ct) { await UniTask.Yield(PlayerLoopTiming.LastPostLateUpdate); UnityEngine.Debug.Log("AWAIT BEFO:" + Time.frameCount); @@ -162,14 +164,16 @@ public class SandboxMain : MonoBehaviour try { - while (true) + while (!ct.IsCancellationRequested) { await handler.UpdateAsync(); + //await handler.UpdateAsync(); + Debug.Log("OK:" + i); } } finally { - UnityEngine.Debug.Log("AWAIT END:" + Time.frameCount); + UnityEngine.Debug.Log("AWAIT END:" + Time.frameCount + ": No," + i); } }