Compare commits

...

7 Commits

Author SHA1 Message Date
neuecc
5d0d29dffd preview3 2020-05-07 11:28:14 +09:00
neuecc
be539fdb10 fix WhenAll,WhenAny 0-length 2020-05-07 11:27:27 +09:00
neuecc
66fa203f7c improv package exporter 2020-05-07 07:38:41 +09:00
neuecc
a78dc55875 preview2 2020-05-07 07:29:31 +09:00
neuecc
84f4d8007d implicit operator UniTask<T> -> UniTask 2020-05-07 07:28:35 +09:00
neuecc
6be955816b Improve AsyncTrigger performance 2020-05-07 07:18:51 +09:00
neuecc
ebe3065c34 delete unitypackage 2020-05-06 03:38:03 +09:00
12 changed files with 200 additions and 87 deletions

2
.gitignore vendored
View File

@@ -155,3 +155,5 @@ src/UniTask/UniTask.Editor.csproj
src/UniTask/UniTask.Tests.csproj src/UniTask/UniTask.Tests.csproj
src/UniTask/UniTask.Tests.Editor.csproj src/UniTask/UniTask.Tests.Editor.csproj
src/UniTask/UniTask.unitypackage

View File

@@ -16,8 +16,16 @@ namespace NetCoreSandbox
static async UniTask<int> outer() static async UniTask<int> outer()
{ {
var v = await DoAsync(); //await Task.WhenAll();
return v;
//var foo = await Task.WhenAny(Array.Empty<Task<int>>());
await UniTask.WhenAny(new UniTask[0]);
return 10;
//var v = await DoAsync();
//return v;
} }

View File

@@ -11,9 +11,18 @@ public static class PackageExporter
[MenuItem("Tools/Export Unitypackage")] [MenuItem("Tools/Export Unitypackage")]
public static void Export() public static void Export()
{ {
// configure
var root = "Plugins/UniTask"; var root = "Plugins/UniTask";
var exportPath = "./UniTask.unitypackage"; var version = Environment.GetEnvironmentVariable("UNITY_PACKAGE_VERSION");
var versionJson = Path.Combine(Application.dataPath, root, "package.json");
if (File.Exists(versionJson))
{
var v = JsonUtility.FromJson<Version>(File.ReadAllText(versionJson));
version = v.version;
}
var fileName = string.IsNullOrEmpty(version) ? "UniTask.unitypackage" : $"UniTask.{version}.unitypackage";
var exportPath = "./" + fileName;
var path = Path.Combine(Application.dataPath, root); var path = Path.Combine(Application.dataPath, root);
var assets = Directory.EnumerateFiles(path, "*", SearchOption.AllDirectories) var assets = Directory.EnumerateFiles(path, "*", SearchOption.AllDirectories)
@@ -30,6 +39,11 @@ public static class PackageExporter
UnityEngine.Debug.Log("Export complete: " + Path.GetFullPath(exportPath)); UnityEngine.Debug.Log("Export complete: " + Path.GetFullPath(exportPath));
} }
public class Version
{
public string version;
}
} }
#endif #endif

View File

@@ -32,11 +32,21 @@ namespace Cysharp.Threading.Tasks.Internal
} }
} }
public static RentArray<T> CopyToRentArray<T>(IEnumerable<T> source) public static RentArray<T> Materialize<T>(IEnumerable<T> source)
{ {
if (source is T[] array)
{
return new RentArray<T>(array, array.Length, null);
}
var defaultCount = 32; var defaultCount = 32;
if (source is ICollection<T> coll) if (source is ICollection<T> coll)
{ {
if (coll.Count == 0)
{
return new RentArray<T>(Array.Empty<T>(), 0, null);
}
defaultCount = coll.Count; defaultCount = coll.Count;
var pool = ArrayPool<T>.Shared; var pool = ArrayPool<T>.Shared;
var buffer = pool.Rent(defaultCount); var buffer = pool.Rent(defaultCount);

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

@@ -11,12 +11,17 @@ namespace Cysharp.Threading.Tasks
{ {
public static UniTask<T[]> WhenAll<T>(params UniTask<T>[] tasks) public static UniTask<T[]> WhenAll<T>(params UniTask<T>[] tasks)
{ {
if (tasks.Length == 0)
{
return UniTask.FromResult(Array.Empty<T>());
}
return new UniTask<T[]>(new WhenAllPromise<T>(tasks, tasks.Length), 0); return new UniTask<T[]>(new WhenAllPromise<T>(tasks, tasks.Length), 0);
} }
public static UniTask<T[]> WhenAll<T>(IEnumerable<UniTask<T>> tasks) public static UniTask<T[]> WhenAll<T>(IEnumerable<UniTask<T>> tasks)
{ {
using (var span = ArrayPoolUtil.CopyToRentArray(tasks)) using (var span = ArrayPoolUtil.Materialize(tasks))
{ {
var promise = new WhenAllPromise<T>(span.Array, span.Length); // consumed array in constructor. var promise = new WhenAllPromise<T>(span.Array, span.Length); // consumed array in constructor.
return new UniTask<T[]>(promise, 0); return new UniTask<T[]>(promise, 0);
@@ -25,12 +30,17 @@ namespace Cysharp.Threading.Tasks
public static UniTask WhenAll(params UniTask[] tasks) public static UniTask WhenAll(params UniTask[] tasks)
{ {
if (tasks.Length == 0)
{
return UniTask.CompletedTask;
}
return new UniTask(new WhenAllPromise(tasks, tasks.Length), 0); return new UniTask(new WhenAllPromise(tasks, tasks.Length), 0);
} }
public static UniTask WhenAll(IEnumerable<UniTask> tasks) public static UniTask WhenAll(IEnumerable<UniTask> tasks)
{ {
using (var span = ArrayPoolUtil.CopyToRentArray(tasks)) using (var span = ArrayPoolUtil.Materialize(tasks))
{ {
var promise = new WhenAllPromise(span.Array, span.Length); // consumed array in constructor. var promise = new WhenAllPromise(span.Array, span.Length); // consumed array in constructor.
return new UniTask(promise, 0); return new UniTask(promise, 0);
@@ -48,6 +58,14 @@ namespace Cysharp.Threading.Tasks
TaskTracker.TrackActiveTask(this, 3); TaskTracker.TrackActiveTask(this, 3);
this.completeCount = 0; this.completeCount = 0;
if (tasksLength == 0)
{
this.result = Array.Empty<T>();
core.TrySetResult(result);
return;
}
this.result = new T[tasksLength]; this.result = new T[tasksLength];
for (int i = 0; i < tasksLength; i++) for (int i = 0; i < tasksLength; i++)
@@ -144,6 +162,12 @@ namespace Cysharp.Threading.Tasks
this.tasksLength = tasksLength; this.tasksLength = tasksLength;
this.completeCount = 0; this.completeCount = 0;
if (tasksLength == 0)
{
core.TrySetResult(AsyncUnit.Default);
return;
}
for (int i = 0; i < tasksLength; i++) for (int i = 0; i < tasksLength; i++)
{ {
UniTask.Awaiter awaiter; UniTask.Awaiter awaiter;

View File

@@ -21,7 +21,7 @@ namespace Cysharp.Threading.Tasks
public static UniTask<(int winArgumentIndex, T result)> WhenAny<T>(IEnumerable<UniTask<T>> tasks) public static UniTask<(int winArgumentIndex, T result)> WhenAny<T>(IEnumerable<UniTask<T>> tasks)
{ {
using (var span = ArrayPoolUtil.CopyToRentArray(tasks)) using (var span = ArrayPoolUtil.Materialize(tasks))
{ {
return new UniTask<(int, T)>(new WhenAnyPromise<T>(span.Array, span.Length), 0); return new UniTask<(int, T)>(new WhenAnyPromise<T>(span.Array, span.Length), 0);
} }
@@ -36,7 +36,7 @@ namespace Cysharp.Threading.Tasks
/// <summary>Return value is winArgumentIndex</summary> /// <summary>Return value is winArgumentIndex</summary>
public static UniTask<int> WhenAny(IEnumerable<UniTask> tasks) public static UniTask<int> WhenAny(IEnumerable<UniTask> tasks)
{ {
using (var span = ArrayPoolUtil.CopyToRentArray(tasks)) using (var span = ArrayPoolUtil.Materialize(tasks))
{ {
return new UniTask<int>(new WhenAnyPromise(span.Array, span.Length), 0); return new UniTask<int>(new WhenAnyPromise(span.Array, span.Length), 0);
} }
@@ -186,6 +186,11 @@ namespace Cysharp.Threading.Tasks
public WhenAnyPromise(UniTask<T>[] tasks, int tasksLength) public WhenAnyPromise(UniTask<T>[] tasks, int tasksLength)
{ {
if (tasksLength == 0)
{
throw new ArgumentException("The tasks argument contains no tasks.");
}
TaskTracker.TrackActiveTask(this, 3); TaskTracker.TrackActiveTask(this, 3);
for (int i = 0; i < tasksLength; i++) for (int i = 0; i < tasksLength; i++)
@@ -277,6 +282,11 @@ namespace Cysharp.Threading.Tasks
public WhenAnyPromise(UniTask[] tasks, int tasksLength) public WhenAnyPromise(UniTask[] tasks, int tasksLength)
{ {
if (tasksLength == 0)
{
throw new ArgumentException("The tasks argument contains no tasks.");
}
TaskTracker.TrackActiveTask(this, 3); TaskTracker.TrackActiveTask(this, 3);
for (int i = 0; i < tasksLength; i++) for (int i = 0; i < tasksLength; i++)

View File

@@ -406,6 +406,11 @@ namespace Cysharp.Threading.Tasks
return new UniTask(this.source, this.token); return new UniTask(this.source, this.token);
} }
public static implicit operator UniTask(UniTask<T> self)
{
return self.AsUniTask();
}
/// <summary> /// <summary>
/// returns (bool IsCanceled, T Result) instead of throws OperationCanceledException. /// returns (bool IsCanceled, T Result) instead of throws OperationCanceledException.
/// </summary> /// </summary>

View File

@@ -1,7 +1,7 @@
{ {
"name": "com.cysharp.unitask", "name": "com.cysharp.unitask",
"displayName": "UniTask", "displayName": "UniTask",
"version": "1.3.1", "version": "2.0.2-preview3",
"unity": "2018.3", "unity": "2018.3",
"description": "Provides an efficient async/await integration to Unity.", "description": "Provides an efficient async/await integration to Unity.",
"keywords": ["async/await", "async", "Task", "UniTask"], "keywords": ["async/await", "async", "Task", "UniTask"],

View File

@@ -124,14 +124,19 @@ 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;
UniTask<int> foo = UniTask.FromResult(10);
Foo(foo);
//ucs = new UniTaskCompletionSource(); //ucs = new UniTaskCompletionSource();
//okButton.onClick.AddListener(async () => //okButton.onClick.AddListener(async () =>
@@ -141,7 +146,7 @@ public class SandboxMain : MonoBehaviour
okButton.onClick.AddListener(() => okButton.onClick.AddListener(() =>
{ {
FooAsync().Forget(); // FooAsync().Forget();
}); });
cancelButton.onClick.AddListener(() => cancelButton.onClick.AddListener(() =>
@@ -154,7 +159,11 @@ public class SandboxMain : MonoBehaviour
}); });
} }
async UniTaskVoid Go(AsyncUpdateTrigger trigger, CancellationToken ct) static void Foo(UniTask t)
{
}
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 +171,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);
} }
} }

Binary file not shown.

Binary file not shown.