Improve AsyncTrigger performance

master
neuecc 2020-05-07 07:18:51 +09:00
parent ebe3065c34
commit 6be955816b
2 changed files with 110 additions and 77 deletions

View File

@ -212,11 +212,16 @@ namespace Cysharp.Threading.Tasks.Triggers
// optimize: many cases, handler is single. // optimize: many cases, handler is single.
AsyncTriggerHandler<T> singleHandler; AsyncTriggerHandler<T> singleHandler;
List<AsyncTriggerHandler<T>> handlers; AsyncTriggerHandler<T>[] handlers;
// when running(in TrySetResult), does not add immediately.
bool isRunning;
AsyncTriggerHandler<T> waitHandler;
MinimumQueue<AsyncTriggerHandler<T>> waitQueue;
public bool TrySetResult(T value) public bool TrySetResult(T value)
{ {
List<Exception> exceptions = null; isRunning = true;
if (singleHandler != null) if (singleHandler != null)
{ {
@ -226,56 +231,44 @@ namespace Cysharp.Threading.Tasks.Triggers
} }
catch (Exception ex) catch (Exception ex)
{ {
if (handlers == null) Debug.LogException(ex);
{
throw;
}
else
{
exceptions = new List<Exception>();
exceptions.Add(ex);
}
} }
} }
if (handlers != null) if (handlers != null)
{ {
// make snapshot for (int i = 0; i < handlers.Length; i++)
var rentArray = ArrayPoolUtil.CopyToRentArray(handlers);
var clearArray = true;
try
{ {
var array = rentArray.Array; if (handlers[i] != null)
var len = rentArray.Length;
for (int i = 0; i < len; i++)
{ {
try try
{ {
((IResolvePromise<T>)array[i]).TrySetResult(value); ((IResolvePromise<T>)handlers[i]).TrySetResult(value);
} }
catch (Exception ex) catch (Exception ex)
{ {
if (exceptions == null) handlers[i] = null;
{ Debug.LogException(ex);
exceptions = new List<Exception>();
}
exceptions.Add(ex);
}
finally
{
array[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; return true;
@ -283,7 +276,7 @@ namespace Cysharp.Threading.Tasks.Triggers
public bool TrySetCanceled(CancellationToken cancellationToken) public bool TrySetCanceled(CancellationToken cancellationToken)
{ {
List<Exception> exceptions = null; isRunning = true;
if (singleHandler != null) if (singleHandler != null)
{ {
@ -293,56 +286,44 @@ namespace Cysharp.Threading.Tasks.Triggers
} }
catch (Exception ex) catch (Exception ex)
{ {
if (handlers == null) Debug.LogException(ex);
{
throw;
}
else
{
exceptions = new List<Exception>();
exceptions.Add(ex);
}
} }
} }
if (handlers != null) if (handlers != null)
{ {
// make snapshot for (int i = 0; i < handlers.Length; i++)
var rentArray = ArrayPoolUtil.CopyToRentArray(handlers);
var clearArray = true;
try
{ {
var array = rentArray.Array; if (handlers[i] != null)
var len = rentArray.Length;
for (int i = 0; i < len; i++)
{ {
try try
{ {
((ICancelPromise)array[i]).TrySetCanceled(cancellationToken); ((ICancelPromise)handlers[i]).TrySetCanceled(cancellationToken);
} }
catch (Exception ex) catch (Exception ex)
{ {
if (exceptions == null) Debug.LogException(ex);
{ handlers[i] = null;
exceptions = new List<Exception>();
}
exceptions.Add(ex);
}
finally
{
array[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; return true;
@ -350,6 +331,22 @@ namespace Cysharp.Threading.Tasks.Triggers
public void Add(AsyncTriggerHandler<T> handler) public void Add(AsyncTriggerHandler<T> handler)
{ {
if (isRunning)
{
if (waitHandler == null)
{
waitHandler = handler;
return;
}
if (waitQueue == null)
{
waitQueue = new MinimumQueue<AsyncTriggerHandler<T>>(4);
}
waitQueue.Enqueue(handler);
return;
}
if (singleHandler == null) if (singleHandler == null)
{ {
singleHandler = handler; singleHandler = handler;
@ -358,12 +355,36 @@ namespace Cysharp.Threading.Tasks.Triggers
{ {
if (handlers == null) if (handlers == null)
{ {
handlers = new List<AsyncTriggerHandler<T>>(); handlers = new AsyncTriggerHandler<T>[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<T>[] array)
{
var newSize = array.Length * 2;
var newArray = new AsyncTriggerHandler<T>[newSize];
Array.Copy(array, 0, newArray, 0, array.Length);
array = newArray;
}
public void Remove(AsyncTriggerHandler<T> handler) public void Remove(AsyncTriggerHandler<T> handler)
{ {
if (singleHandler == handler) if (singleHandler == handler)
@ -374,7 +395,15 @@ namespace Cysharp.Threading.Tasks.Triggers
{ {
if (handlers != null) if (handlers != null)
{ {
handlers.Remove(handler); for (int i = 0; i < handlers.Length; i++)
{
if (handlers[i] == handler)
{
// fill null.
handlers[i] = null;
return;
}
}
} }
} }
} }

View File

@ -124,9 +124,11 @@ public class SandboxMain : MonoBehaviour
CancellationTokenSource cts = new CancellationTokenSource(); CancellationTokenSource cts = new CancellationTokenSource();
var trigger = this.GetAsyncUpdateTrigger(); var trigger = this.GetAsyncUpdateTrigger();
Go(trigger, cts.Token).Forget(); Go(trigger, 1, cts.Token).Forget();
//Go(trigger).Forget(); Go(trigger, 2, cts.Token).Forget();
//Go(trigger).Forget(); Go(trigger, 3, cts.Token).Forget();
Go(trigger, 4, cts.Token).Forget();
Go(trigger, 5, cts.Token).Forget();
Application.logMessageReceived += Application_logMessageReceived; Application.logMessageReceived += Application_logMessageReceived;
@ -141,7 +143,7 @@ public class SandboxMain : MonoBehaviour
okButton.onClick.AddListener(() => okButton.onClick.AddListener(() =>
{ {
FooAsync().Forget(); // FooAsync().Forget();
}); });
cancelButton.onClick.AddListener(() => 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); await UniTask.Yield(PlayerLoopTiming.LastPostLateUpdate);
UnityEngine.Debug.Log("AWAIT BEFO:" + Time.frameCount); UnityEngine.Debug.Log("AWAIT BEFO:" + Time.frameCount);
@ -162,14 +164,16 @@ public class SandboxMain : MonoBehaviour
try try
{ {
while (true) while (!ct.IsCancellationRequested)
{ {
await handler.UpdateAsync(); await handler.UpdateAsync();
//await handler.UpdateAsync();
Debug.Log("OK:" + i);
} }
} }
finally finally
{ {
UnityEngine.Debug.Log("AWAIT END:" + Time.frameCount); UnityEngine.Debug.Log("AWAIT END:" + Time.frameCount + ": No," + i);
} }
} }