mirror of
https://github.com/Cysharp/UniTask.git
synced 2026-05-15 19:40:09 +00:00
Compare commits
8 Commits
2.0.11-rc8
...
2.0.12-rc9
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
21bf08a6b3 | ||
|
|
d5db96b913 | ||
|
|
a8455af16d | ||
|
|
2290b14532 | ||
|
|
90c5a6311b | ||
|
|
6e0ad3623b | ||
|
|
005e02a1fa | ||
|
|
10fb8060fa |
@@ -59,16 +59,22 @@ namespace Cysharp.Threading.Tasks
|
||||
|
||||
#if NETCOREAPP3_1
|
||||
|
||||
public sealed class ThreadPoolWorkItem : IThreadPoolWorkItem
|
||||
sealed class ThreadPoolWorkItem : IThreadPoolWorkItem, ITaskPoolNode<ThreadPoolWorkItem>
|
||||
{
|
||||
static readonly ConcurrentQueue<ThreadPoolWorkItem> pool = new ConcurrentQueue<ThreadPoolWorkItem>();
|
||||
static TaskPool<ThreadPoolWorkItem> pool;
|
||||
public ThreadPoolWorkItem NextNode { get; set; }
|
||||
|
||||
static ThreadPoolWorkItem()
|
||||
{
|
||||
TaskPoolMonitor.RegisterSizeGetter(typeof(ThreadPoolWorkItem), () => pool.Size);
|
||||
}
|
||||
|
||||
Action continuation;
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static ThreadPoolWorkItem Create(Action continuation)
|
||||
{
|
||||
if (!pool.TryDequeue(out var item))
|
||||
if (!pool.TryPop(out var item))
|
||||
{
|
||||
item = new ThreadPoolWorkItem();
|
||||
}
|
||||
@@ -82,9 +88,11 @@ namespace Cysharp.Threading.Tasks
|
||||
{
|
||||
var call = continuation;
|
||||
continuation = null;
|
||||
pool.Enqueue(this);
|
||||
|
||||
call.Invoke();
|
||||
if (call != null)
|
||||
{
|
||||
pool.TryPush(this);
|
||||
call.Invoke();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -29,7 +29,12 @@ public class AllocationCheck
|
||||
{
|
||||
for (int i = 0; i < InnerOps; i++)
|
||||
{
|
||||
await Core();
|
||||
var a = Core();
|
||||
var b = Core();
|
||||
var c = Core();
|
||||
await a;
|
||||
await b;
|
||||
await c;
|
||||
}
|
||||
|
||||
static async UniTask Core()
|
||||
@@ -46,7 +51,12 @@ public class AllocationCheck
|
||||
var sum = 0;
|
||||
for (int i = 0; i < InnerOps; i++)
|
||||
{
|
||||
sum += await Core();
|
||||
var a = Core();
|
||||
var b = Core();
|
||||
var c = Core();
|
||||
sum += await a;
|
||||
sum += await b;
|
||||
sum += await c;
|
||||
}
|
||||
return sum;
|
||||
|
||||
@@ -59,14 +69,16 @@ public class AllocationCheck
|
||||
}
|
||||
}
|
||||
|
||||
[Benchmark(OperationsPerInvoke = InnerOps)]
|
||||
public Task ViaUniTaskVoid()
|
||||
//[Benchmark(OperationsPerInvoke = InnerOps)]
|
||||
//[Benchmark]
|
||||
public void ViaUniTaskVoid()
|
||||
{
|
||||
for (int i = 0; i < InnerOps; i++)
|
||||
{
|
||||
Core().Forget();
|
||||
Core().Forget();
|
||||
Core().Forget();
|
||||
}
|
||||
return Task.CompletedTask;
|
||||
|
||||
static async UniTaskVoid Core()
|
||||
{
|
||||
@@ -75,6 +87,46 @@ public class AllocationCheck
|
||||
await new TestAwaiter(false, UniTaskStatus.Succeeded);
|
||||
}
|
||||
}
|
||||
|
||||
struct Foo : IAsyncStateMachine
|
||||
{
|
||||
public AsyncUniTaskVoidMethodBuilder builder;
|
||||
public TestAwaiter awaiter;
|
||||
public TestAwaiter awaiterawaiter;
|
||||
|
||||
public int state;
|
||||
|
||||
public void MoveNext()
|
||||
{
|
||||
switch (state)
|
||||
{
|
||||
case -1:
|
||||
awaiterawaiter = awaiter.GetAwaiter();
|
||||
if (awaiterawaiter.IsCompleted)
|
||||
{
|
||||
goto case 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
state = 0;
|
||||
builder.AwaitUnsafeOnCompleted(ref awaiterawaiter, ref this);
|
||||
return;
|
||||
}
|
||||
|
||||
case 0:
|
||||
default:
|
||||
goto END;
|
||||
}
|
||||
|
||||
END:
|
||||
builder.SetResult();
|
||||
}
|
||||
|
||||
public void SetStateMachine(IAsyncStateMachine stateMachine)
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public class TaskTestException : Exception
|
||||
@@ -170,7 +222,15 @@ public struct TestAwaiter<T> : ICriticalNotifyCompletion
|
||||
|
||||
public sealed class ThreadPoolWorkItem : IThreadPoolWorkItem
|
||||
{
|
||||
static readonly ConcurrentQueue<ThreadPoolWorkItem> pool = new ConcurrentQueue<ThreadPoolWorkItem>();
|
||||
public static readonly ConcurrentQueue<ThreadPoolWorkItem> pool = new ConcurrentQueue<ThreadPoolWorkItem>();
|
||||
|
||||
public static void CreatePoolItems(int count)
|
||||
{
|
||||
for (int i = 0; i < count; i++)
|
||||
{
|
||||
pool.Enqueue(new ThreadPoolWorkItem());
|
||||
}
|
||||
}
|
||||
|
||||
Action continuation;
|
||||
|
||||
|
||||
@@ -37,7 +37,7 @@ public class BenchmarkConfig : ManualConfig
|
||||
public BenchmarkConfig()
|
||||
{
|
||||
AddDiagnoser(MemoryDiagnoser.Default);
|
||||
AddJob(Job.ShortRun.WithLaunchCount(1).WithIterationCount(1).WithWarmupCount(1));
|
||||
AddJob(Job.ShortRun.WithLaunchCount(1).WithIterationCount(1).WithWarmupCount(1)/*.RunOncePerIteration()*/);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -198,38 +198,67 @@ namespace NetCoreSandbox
|
||||
static async Task Main(string[] args)
|
||||
{
|
||||
#if !DEBUG
|
||||
|
||||
//await new AllocationCheck().ViaUniTaskVoid();
|
||||
//Console.ReadLine();
|
||||
BenchmarkDotNet.Running.BenchmarkSwitcher.FromAssembly(typeof(Program).Assembly).Run(args);
|
||||
|
||||
//await new ComparisonBenchmarks().ViaUniTaskT();
|
||||
return;
|
||||
#endif
|
||||
// await new AllocationCheck().ViaUniTaskVoid();
|
||||
|
||||
|
||||
AsyncTest().Forget();
|
||||
// AsyncTest().Forget();
|
||||
|
||||
|
||||
//AsyncTest().Forget();
|
||||
|
||||
// AsyncTest().Forget();
|
||||
|
||||
ThreadPool.SetMinThreads(100, 100);
|
||||
|
||||
//List<UniTask<int>> list = new List<UniTask<int>>();
|
||||
for (int i = 0; i < short.MaxValue; i++)
|
||||
{
|
||||
//// list.Add(AsyncTest());
|
||||
await YieldCore();
|
||||
}
|
||||
//await UniTask.WhenAll(list);
|
||||
|
||||
//Console.WriteLine("TOGO");
|
||||
|
||||
//var a = await AsyncTest();
|
||||
//var b = AsyncTest();
|
||||
//var c = AsyncTest();
|
||||
await YieldCore();
|
||||
|
||||
//await b;
|
||||
//await c;
|
||||
|
||||
|
||||
foreach (var item in Cysharp.Threading.Tasks.Internal.TaskPoolMonitor.GetCacheSizeInfo())
|
||||
{
|
||||
Console.WriteLine(item);
|
||||
}
|
||||
|
||||
await UniTask.Yield();
|
||||
Console.ReadLine();
|
||||
}
|
||||
|
||||
static async UniTask YieldCore()
|
||||
{
|
||||
await UniTask.Yield();
|
||||
}
|
||||
|
||||
#pragma warning disable CS1998
|
||||
|
||||
|
||||
static async UniTaskVoid AsyncTest()
|
||||
static async UniTask<int> AsyncTest()
|
||||
{
|
||||
// empty
|
||||
// empty
|
||||
await new TestAwaiter(false, UniTaskStatus.Succeeded);
|
||||
await new TestAwaiter(true, UniTaskStatus.Succeeded);
|
||||
await new TestAwaiter(false, UniTaskStatus.Succeeded);
|
||||
|
||||
|
||||
Console.WriteLine("foo");
|
||||
//return 10;
|
||||
return 10;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -12,9 +12,8 @@ namespace Cysharp.Threading.Tasks.CompilerServices
|
||||
[StructLayout(LayoutKind.Auto)]
|
||||
public struct AsyncUniTaskMethodBuilder
|
||||
{
|
||||
// cache items.
|
||||
AutoResetUniTaskCompletionSource promise;
|
||||
internal IMoveNextRunner runner;
|
||||
internal IMoveNextRunnerPromise runnerPromise;
|
||||
Exception ex;
|
||||
|
||||
// 1. Static Create method.
|
||||
[DebuggerHidden]
|
||||
@@ -31,18 +30,18 @@ namespace Cysharp.Threading.Tasks.CompilerServices
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
get
|
||||
{
|
||||
if (promise != null)
|
||||
if (runnerPromise != null)
|
||||
{
|
||||
return promise.Task;
|
||||
return runnerPromise.Task;
|
||||
}
|
||||
|
||||
if (runner == null)
|
||||
else if (ex != null)
|
||||
{
|
||||
return UniTask.FromException(ex);
|
||||
}
|
||||
else
|
||||
{
|
||||
return UniTask.CompletedTask;
|
||||
}
|
||||
|
||||
promise = AutoResetUniTaskCompletionSource.Create();
|
||||
return promise.Task;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -50,22 +49,13 @@ namespace Cysharp.Threading.Tasks.CompilerServices
|
||||
[DebuggerHidden]
|
||||
public void SetException(Exception exception)
|
||||
{
|
||||
var p = promise; // after return, promise will clear so require to store local.
|
||||
|
||||
// runner is finished, return first.
|
||||
if (runner != null)
|
||||
if (runnerPromise == null)
|
||||
{
|
||||
runner.Return();
|
||||
runner = null;
|
||||
}
|
||||
|
||||
if (p != null)
|
||||
{
|
||||
p.TrySetException(exception);
|
||||
ex = exception;
|
||||
}
|
||||
else
|
||||
{
|
||||
promise = AutoResetUniTaskCompletionSource.CreateFromException(exception, out _);
|
||||
runnerPromise.SetException(exception);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -73,18 +63,9 @@ namespace Cysharp.Threading.Tasks.CompilerServices
|
||||
[DebuggerHidden]
|
||||
public void SetResult()
|
||||
{
|
||||
var p = promise; // after return, promise will clear so require to store local.
|
||||
|
||||
// runner is finished, return first.
|
||||
if (runner != null)
|
||||
if (runnerPromise != null)
|
||||
{
|
||||
runner.Return();
|
||||
runner = null;
|
||||
}
|
||||
|
||||
if (p != null)
|
||||
{
|
||||
p.TrySetResult();
|
||||
runnerPromise.SetResult();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -94,16 +75,12 @@ namespace Cysharp.Threading.Tasks.CompilerServices
|
||||
where TAwaiter : INotifyCompletion
|
||||
where TStateMachine : IAsyncStateMachine
|
||||
{
|
||||
if (promise == null)
|
||||
if (runnerPromise == null)
|
||||
{
|
||||
promise = AutoResetUniTaskCompletionSource.Create();
|
||||
}
|
||||
if (runner == null)
|
||||
{
|
||||
MoveNextRunner<TStateMachine>.SetRunner(ref this, ref stateMachine);
|
||||
AsyncUniTask<TStateMachine>.SetStateMachine(ref this, ref stateMachine);
|
||||
}
|
||||
|
||||
awaiter.OnCompleted(runner.CallMoveNext);
|
||||
awaiter.OnCompleted(runnerPromise.MoveNext);
|
||||
}
|
||||
|
||||
// 6. AwaitUnsafeOnCompleted
|
||||
@@ -113,16 +90,12 @@ namespace Cysharp.Threading.Tasks.CompilerServices
|
||||
where TAwaiter : ICriticalNotifyCompletion
|
||||
where TStateMachine : IAsyncStateMachine
|
||||
{
|
||||
if (promise == null)
|
||||
if (runnerPromise == null)
|
||||
{
|
||||
promise = AutoResetUniTaskCompletionSource.Create();
|
||||
}
|
||||
if (runner == null)
|
||||
{
|
||||
MoveNextRunner<TStateMachine>.SetRunner(ref this, ref stateMachine);
|
||||
AsyncUniTask<TStateMachine>.SetStateMachine(ref this, ref stateMachine);
|
||||
}
|
||||
|
||||
awaiter.UnsafeOnCompleted(runner.CallMoveNext);
|
||||
awaiter.UnsafeOnCompleted(runnerPromise.MoveNext);
|
||||
}
|
||||
|
||||
// 7. Start
|
||||
@@ -160,9 +133,8 @@ namespace Cysharp.Threading.Tasks.CompilerServices
|
||||
[StructLayout(LayoutKind.Auto)]
|
||||
public struct AsyncUniTaskMethodBuilder<T>
|
||||
{
|
||||
// cache items.
|
||||
AutoResetUniTaskCompletionSource<T> promise;
|
||||
internal IMoveNextRunner runner;
|
||||
internal IMoveNextRunnerPromise<T> runnerPromise;
|
||||
Exception ex;
|
||||
T result;
|
||||
|
||||
// 1. Static Create method.
|
||||
@@ -179,18 +151,18 @@ namespace Cysharp.Threading.Tasks.CompilerServices
|
||||
{
|
||||
get
|
||||
{
|
||||
if (promise != null)
|
||||
if (runnerPromise != null)
|
||||
{
|
||||
return promise.Task;
|
||||
return runnerPromise.Task;
|
||||
}
|
||||
|
||||
if (runner == null)
|
||||
else if (ex != null)
|
||||
{
|
||||
return UniTask.FromException<T>(ex);
|
||||
}
|
||||
else
|
||||
{
|
||||
return UniTask.FromResult(result);
|
||||
}
|
||||
|
||||
promise = AutoResetUniTaskCompletionSource<T>.Create();
|
||||
return promise.Task;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -198,22 +170,13 @@ namespace Cysharp.Threading.Tasks.CompilerServices
|
||||
[DebuggerHidden]
|
||||
public void SetException(Exception exception)
|
||||
{
|
||||
var p = promise; // after return, promise will clear so require to store local.
|
||||
|
||||
// runner is finished, return first.
|
||||
if (runner != null)
|
||||
if (runnerPromise == null)
|
||||
{
|
||||
runner.Return();
|
||||
runner = null;
|
||||
}
|
||||
|
||||
if (p == null)
|
||||
{
|
||||
promise = AutoResetUniTaskCompletionSource<T>.CreateFromException(exception, out _);
|
||||
ex = exception;
|
||||
}
|
||||
else
|
||||
{
|
||||
p.TrySetException(exception);
|
||||
runnerPromise.SetException(exception);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -221,22 +184,13 @@ namespace Cysharp.Threading.Tasks.CompilerServices
|
||||
[DebuggerHidden]
|
||||
public void SetResult(T result)
|
||||
{
|
||||
var p = promise; // after return, promise will clear so require to store local.
|
||||
|
||||
// runner is finished, return first.
|
||||
if (runner != null)
|
||||
{
|
||||
runner.Return();
|
||||
runner = null;
|
||||
}
|
||||
|
||||
if (p == null)
|
||||
if (runnerPromise == null)
|
||||
{
|
||||
this.result = result;
|
||||
}
|
||||
else
|
||||
{
|
||||
p.TrySetResult(result);
|
||||
runnerPromise.SetResult(result);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -246,16 +200,12 @@ namespace Cysharp.Threading.Tasks.CompilerServices
|
||||
where TAwaiter : INotifyCompletion
|
||||
where TStateMachine : IAsyncStateMachine
|
||||
{
|
||||
if (promise == null)
|
||||
if (runnerPromise == null)
|
||||
{
|
||||
promise = AutoResetUniTaskCompletionSource<T>.Create();
|
||||
}
|
||||
if (runner == null)
|
||||
{
|
||||
MoveNextRunner<TStateMachine>.SetRunner(ref this, ref stateMachine);
|
||||
AsyncUniTask<TStateMachine, T>.SetStateMachine(ref this, ref stateMachine);
|
||||
}
|
||||
|
||||
awaiter.OnCompleted(runner.CallMoveNext);
|
||||
awaiter.OnCompleted(runnerPromise.MoveNext);
|
||||
}
|
||||
|
||||
// 6. AwaitUnsafeOnCompleted
|
||||
@@ -265,16 +215,12 @@ namespace Cysharp.Threading.Tasks.CompilerServices
|
||||
where TAwaiter : ICriticalNotifyCompletion
|
||||
where TStateMachine : IAsyncStateMachine
|
||||
{
|
||||
if (promise == null)
|
||||
if (runnerPromise == null)
|
||||
{
|
||||
promise = AutoResetUniTaskCompletionSource<T>.Create();
|
||||
}
|
||||
if (runner == null)
|
||||
{
|
||||
MoveNextRunner<TStateMachine>.SetRunner(ref this, ref stateMachine);
|
||||
AsyncUniTask<TStateMachine, T>.SetStateMachine(ref this, ref stateMachine);
|
||||
}
|
||||
|
||||
awaiter.UnsafeOnCompleted(runner.CallMoveNext);
|
||||
awaiter.UnsafeOnCompleted(runnerPromise.MoveNext);
|
||||
}
|
||||
|
||||
// 7. Start
|
||||
|
||||
@@ -4,10 +4,12 @@
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Security;
|
||||
|
||||
namespace Cysharp.Threading.Tasks.CompilerServices
|
||||
{
|
||||
[StructLayout(LayoutKind.Auto)]
|
||||
public struct AsyncUniTaskVoidMethodBuilder
|
||||
{
|
||||
internal IMoveNextRunner runner;
|
||||
@@ -65,10 +67,10 @@ namespace Cysharp.Threading.Tasks.CompilerServices
|
||||
{
|
||||
if (runner == null)
|
||||
{
|
||||
MoveNextRunner<TStateMachine>.SetRunner(ref this, ref stateMachine);
|
||||
AsyncUniTaskVoid<TStateMachine>.SetStateMachine(ref this, ref stateMachine);
|
||||
}
|
||||
|
||||
awaiter.OnCompleted(runner.CallMoveNext);
|
||||
awaiter.OnCompleted(runner.MoveNext);
|
||||
}
|
||||
|
||||
// 6. AwaitUnsafeOnCompleted
|
||||
@@ -80,10 +82,10 @@ namespace Cysharp.Threading.Tasks.CompilerServices
|
||||
{
|
||||
if (runner == null)
|
||||
{
|
||||
MoveNextRunner<TStateMachine>.SetRunner(ref this, ref stateMachine);
|
||||
AsyncUniTaskVoid<TStateMachine>.SetStateMachine(ref this, ref stateMachine);
|
||||
}
|
||||
|
||||
awaiter.UnsafeOnCompleted(runner.CallMoveNext);
|
||||
awaiter.UnsafeOnCompleted(runner.MoveNext);
|
||||
}
|
||||
|
||||
// 7. Start
|
||||
|
||||
@@ -1,68 +1,72 @@
|
||||
|
||||
#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member
|
||||
#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member
|
||||
|
||||
using Cysharp.Threading.Tasks.Internal;
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.Runtime.CompilerServices;
|
||||
using Cysharp.Threading.Tasks.Internal;
|
||||
|
||||
namespace Cysharp.Threading.Tasks.CompilerServices
|
||||
{
|
||||
internal interface IMoveNextRunner
|
||||
public interface IMoveNextRunner
|
||||
{
|
||||
Action CallMoveNext { get; }
|
||||
Action MoveNext { get; }
|
||||
void Return();
|
||||
}
|
||||
|
||||
internal sealed class MoveNextRunner<TStateMachine> : IMoveNextRunner, IPromisePoolItem
|
||||
internal interface IMoveNextRunnerPromise : IUniTaskSource
|
||||
{
|
||||
Action MoveNext { get; }
|
||||
UniTask Task { get; }
|
||||
void SetResult();
|
||||
void SetException(Exception exception);
|
||||
}
|
||||
|
||||
internal interface IMoveNextRunnerPromise<T> : IUniTaskSource<T>
|
||||
{
|
||||
Action MoveNext { get; }
|
||||
UniTask<T> Task { get; }
|
||||
void SetResult(T result);
|
||||
void SetException(Exception exception);
|
||||
}
|
||||
|
||||
internal sealed class AsyncUniTaskVoid<TStateMachine> : IMoveNextRunner, ITaskPoolNode<AsyncUniTaskVoid<TStateMachine>>, IUniTaskSource
|
||||
where TStateMachine : IAsyncStateMachine
|
||||
{
|
||||
static PromisePool<MoveNextRunner<TStateMachine>> pool = new PromisePool<MoveNextRunner<TStateMachine>>();
|
||||
static TaskPool<AsyncUniTaskVoid<TStateMachine>> pool;
|
||||
|
||||
TStateMachine stateMachine;
|
||||
internal readonly Action callMoveNext;
|
||||
|
||||
public Action CallMoveNext => callMoveNext;
|
||||
public Action MoveNext { get; }
|
||||
|
||||
MoveNextRunner()
|
||||
public AsyncUniTaskVoid()
|
||||
{
|
||||
callMoveNext = Run;
|
||||
MoveNext = Run;
|
||||
}
|
||||
|
||||
public static void SetRunner(ref AsyncUniTaskMethodBuilder builder, ref TStateMachine stateMachine)
|
||||
public static void SetStateMachine(ref AsyncUniTaskVoidMethodBuilder builder, ref TStateMachine stateMachine)
|
||||
{
|
||||
var result = pool.TryRent();
|
||||
if (result == null)
|
||||
if (!pool.TryPop(out var result))
|
||||
{
|
||||
result = new MoveNextRunner<TStateMachine>();
|
||||
result = new AsyncUniTaskVoid<TStateMachine>();
|
||||
}
|
||||
TaskTracker.TrackActiveTask(result, 3);
|
||||
|
||||
builder.runner = result; // set runner before copied.
|
||||
result.stateMachine = stateMachine; // copy struct StateMachine(in release build).
|
||||
}
|
||||
|
||||
public static void SetRunner<T>(ref AsyncUniTaskMethodBuilder<T> builder, ref TStateMachine stateMachine)
|
||||
static AsyncUniTaskVoid()
|
||||
{
|
||||
var result = pool.TryRent();
|
||||
if (result == null)
|
||||
{
|
||||
result = new MoveNextRunner<TStateMachine>();
|
||||
}
|
||||
|
||||
builder.runner = result; // set runner before copied.
|
||||
result.stateMachine = stateMachine; // copy struct StateMachine(in release build).
|
||||
TaskPoolMonitor.RegisterSizeGetter(typeof(AsyncUniTaskVoid<TStateMachine>), () => pool.Size);
|
||||
}
|
||||
|
||||
public static void SetRunner(ref AsyncUniTaskVoidMethodBuilder builder, ref TStateMachine stateMachine)
|
||||
{
|
||||
var result = pool.TryRent();
|
||||
if (result == null)
|
||||
{
|
||||
result = new MoveNextRunner<TStateMachine>();
|
||||
}
|
||||
public AsyncUniTaskVoid<TStateMachine> NextNode { get; set; }
|
||||
|
||||
builder.runner = result; // set runner before copied.
|
||||
result.stateMachine = stateMachine; // copy struct StateMachine(in release build).
|
||||
public void Return()
|
||||
{
|
||||
TaskTracker.RemoveTracking(this);
|
||||
stateMachine = default;
|
||||
pool.TryPush(this);
|
||||
}
|
||||
|
||||
[DebuggerHidden]
|
||||
@@ -72,14 +76,252 @@ namespace Cysharp.Threading.Tasks.CompilerServices
|
||||
stateMachine.MoveNext();
|
||||
}
|
||||
|
||||
public void Return()
|
||||
// dummy interface implementation for TaskTracker.
|
||||
|
||||
UniTaskStatus IUniTaskSource.GetStatus(short token)
|
||||
{
|
||||
pool.TryReturn(this);
|
||||
return UniTaskStatus.Pending;
|
||||
}
|
||||
|
||||
void IPromisePoolItem.Reset()
|
||||
UniTaskStatus IUniTaskSource.UnsafeGetStatus()
|
||||
{
|
||||
return UniTaskStatus.Pending;
|
||||
}
|
||||
|
||||
void IUniTaskSource.OnCompleted(Action<object> continuation, object state, short token)
|
||||
{
|
||||
}
|
||||
|
||||
void IUniTaskSource.GetResult(short token)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
internal sealed class AsyncUniTask<TStateMachine> : IMoveNextRunnerPromise, IUniTaskSource, ITaskPoolNode<AsyncUniTask<TStateMachine>>
|
||||
where TStateMachine : IAsyncStateMachine
|
||||
{
|
||||
static TaskPool<AsyncUniTask<TStateMachine>> pool;
|
||||
|
||||
TStateMachine stateMachine;
|
||||
|
||||
public Action MoveNext { get; }
|
||||
|
||||
UniTaskCompletionSourceCore<AsyncUnit> core;
|
||||
|
||||
AsyncUniTask()
|
||||
{
|
||||
MoveNext = Run;
|
||||
}
|
||||
|
||||
public static void SetStateMachine(ref AsyncUniTaskMethodBuilder builder, ref TStateMachine stateMachine)
|
||||
{
|
||||
if (!pool.TryPop(out var result))
|
||||
{
|
||||
result = new AsyncUniTask<TStateMachine>();
|
||||
}
|
||||
TaskTracker.TrackActiveTask(result, 3);
|
||||
|
||||
builder.runnerPromise = result; // set runner before copied.
|
||||
result.stateMachine = stateMachine; // copy struct StateMachine(in release build).
|
||||
}
|
||||
|
||||
public AsyncUniTask<TStateMachine> NextNode { get; set; }
|
||||
|
||||
static AsyncUniTask()
|
||||
{
|
||||
TaskPoolMonitor.RegisterSizeGetter(typeof(AsyncUniTask<TStateMachine>), () => pool.Size);
|
||||
}
|
||||
|
||||
bool TryReturn()
|
||||
{
|
||||
TaskTracker.RemoveTracking(this);
|
||||
core.Reset();
|
||||
stateMachine = default;
|
||||
return pool.TryPush(this);
|
||||
}
|
||||
|
||||
[DebuggerHidden]
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
void Run()
|
||||
{
|
||||
stateMachine.MoveNext();
|
||||
}
|
||||
|
||||
public UniTask Task
|
||||
{
|
||||
[DebuggerHidden]
|
||||
get
|
||||
{
|
||||
return new UniTask(this, core.Version);
|
||||
}
|
||||
}
|
||||
|
||||
[DebuggerHidden]
|
||||
public void SetResult()
|
||||
{
|
||||
core.TrySetResult(AsyncUnit.Default);
|
||||
}
|
||||
|
||||
[DebuggerHidden]
|
||||
public void SetException(Exception exception)
|
||||
{
|
||||
core.TrySetException(exception);
|
||||
}
|
||||
|
||||
[DebuggerHidden]
|
||||
public void GetResult(short token)
|
||||
{
|
||||
try
|
||||
{
|
||||
core.GetResult(token);
|
||||
}
|
||||
finally
|
||||
{
|
||||
TryReturn();
|
||||
}
|
||||
}
|
||||
|
||||
[DebuggerHidden]
|
||||
public UniTaskStatus GetStatus(short token)
|
||||
{
|
||||
return core.GetStatus(token);
|
||||
}
|
||||
|
||||
[DebuggerHidden]
|
||||
public UniTaskStatus UnsafeGetStatus()
|
||||
{
|
||||
return core.UnsafeGetStatus();
|
||||
}
|
||||
|
||||
[DebuggerHidden]
|
||||
public void OnCompleted(Action<object> continuation, object state, short token)
|
||||
{
|
||||
core.OnCompleted(continuation, state, token);
|
||||
}
|
||||
|
||||
~AsyncUniTask()
|
||||
{
|
||||
if (TryReturn())
|
||||
{
|
||||
GC.ReRegisterForFinalize(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal sealed class AsyncUniTask<TStateMachine, T> : IMoveNextRunnerPromise<T>, IUniTaskSource<T>, ITaskPoolNode<AsyncUniTask<TStateMachine, T>>
|
||||
where TStateMachine : IAsyncStateMachine
|
||||
{
|
||||
static TaskPool<AsyncUniTask<TStateMachine, T>> pool;
|
||||
|
||||
TStateMachine stateMachine;
|
||||
|
||||
public Action MoveNext { get; }
|
||||
|
||||
UniTaskCompletionSourceCore<T> core;
|
||||
|
||||
AsyncUniTask()
|
||||
{
|
||||
MoveNext = Run;
|
||||
}
|
||||
|
||||
public static void SetStateMachine(ref AsyncUniTaskMethodBuilder<T> builder, ref TStateMachine stateMachine)
|
||||
{
|
||||
if (!pool.TryPop(out var result))
|
||||
{
|
||||
result = new AsyncUniTask<TStateMachine, T>();
|
||||
}
|
||||
TaskTracker.TrackActiveTask(result, 3);
|
||||
|
||||
builder.runnerPromise = result; // set runner before copied.
|
||||
result.stateMachine = stateMachine; // copy struct StateMachine(in release build).
|
||||
}
|
||||
|
||||
public AsyncUniTask<TStateMachine, T> NextNode { get; set; }
|
||||
|
||||
static AsyncUniTask()
|
||||
{
|
||||
TaskPoolMonitor.RegisterSizeGetter(typeof(AsyncUniTask<TStateMachine, T>), () => pool.Size);
|
||||
}
|
||||
|
||||
bool TryReturn()
|
||||
{
|
||||
TaskTracker.RemoveTracking(this);
|
||||
core.Reset();
|
||||
stateMachine = default;
|
||||
return pool.TryPush(this);
|
||||
}
|
||||
|
||||
[DebuggerHidden]
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
void Run()
|
||||
{
|
||||
stateMachine.MoveNext();
|
||||
}
|
||||
|
||||
public UniTask<T> Task
|
||||
{
|
||||
[DebuggerHidden]
|
||||
get
|
||||
{
|
||||
return new UniTask<T>(this, core.Version);
|
||||
}
|
||||
}
|
||||
|
||||
[DebuggerHidden]
|
||||
public void SetResult(T result)
|
||||
{
|
||||
core.TrySetResult(result);
|
||||
}
|
||||
|
||||
[DebuggerHidden]
|
||||
public void SetException(Exception exception)
|
||||
{
|
||||
core.TrySetException(exception);
|
||||
}
|
||||
|
||||
[DebuggerHidden]
|
||||
public T GetResult(short token)
|
||||
{
|
||||
try
|
||||
{
|
||||
return core.GetResult(token);
|
||||
}
|
||||
finally
|
||||
{
|
||||
TryReturn();
|
||||
}
|
||||
}
|
||||
|
||||
[DebuggerHidden]
|
||||
void IUniTaskSource.GetResult(short token)
|
||||
{
|
||||
GetResult(token);
|
||||
}
|
||||
|
||||
[DebuggerHidden]
|
||||
public UniTaskStatus GetStatus(short token)
|
||||
{
|
||||
return core.GetStatus(token);
|
||||
}
|
||||
|
||||
[DebuggerHidden]
|
||||
public UniTaskStatus UnsafeGetStatus()
|
||||
{
|
||||
return core.UnsafeGetStatus();
|
||||
}
|
||||
|
||||
[DebuggerHidden]
|
||||
public void OnCompleted(Action<object> continuation, object state, short token)
|
||||
{
|
||||
core.OnCompleted(continuation, state, token);
|
||||
}
|
||||
|
||||
~AsyncUniTask()
|
||||
{
|
||||
if (TryReturn())
|
||||
{
|
||||
GC.ReRegisterForFinalize(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -30,9 +30,15 @@ namespace Cysharp.Threading.Tasks
|
||||
return new UniTask(EnumeratorPromise.Create(enumerator, timing, cancellationToken, out var token), token);
|
||||
}
|
||||
|
||||
class EnumeratorPromise : IUniTaskSource, IPlayerLoopItem, IPromisePoolItem
|
||||
sealed class EnumeratorPromise : IUniTaskSource, IPlayerLoopItem, ITaskPoolNode<EnumeratorPromise>
|
||||
{
|
||||
static readonly PromisePool<EnumeratorPromise> pool = new PromisePool<EnumeratorPromise>();
|
||||
static TaskPool<EnumeratorPromise> pool;
|
||||
public EnumeratorPromise NextNode { get; set; }
|
||||
|
||||
static EnumeratorPromise()
|
||||
{
|
||||
TaskPoolMonitor.RegisterSizeGetter(typeof(EnumeratorPromise), () => pool.Size);
|
||||
}
|
||||
|
||||
IEnumerator innerEnumerator;
|
||||
CancellationToken cancellationToken;
|
||||
@@ -50,13 +56,15 @@ namespace Cysharp.Threading.Tasks
|
||||
return AutoResetUniTaskCompletionSource.CreateFromCanceled(cancellationToken, out token);
|
||||
}
|
||||
|
||||
var result = pool.TryRent() ?? new EnumeratorPromise();
|
||||
if (!pool.TryPop(out var result))
|
||||
{
|
||||
result = new EnumeratorPromise();
|
||||
}
|
||||
TaskTracker.TrackActiveTask(result, 3);
|
||||
|
||||
result.innerEnumerator = ConsumeEnumerator(innerEnumerator);
|
||||
result.cancellationToken = cancellationToken;
|
||||
|
||||
TaskTracker.TrackActiveTask(result, 3);
|
||||
|
||||
PlayerLoopHelper.AddAction(timing, result);
|
||||
|
||||
token = result.core.Version;
|
||||
@@ -67,12 +75,11 @@ namespace Cysharp.Threading.Tasks
|
||||
{
|
||||
try
|
||||
{
|
||||
TaskTracker.RemoveTracking(this);
|
||||
core.GetResult(token);
|
||||
}
|
||||
finally
|
||||
{
|
||||
pool.TryReturn(this);
|
||||
TryReturn();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -116,16 +123,18 @@ namespace Cysharp.Threading.Tasks
|
||||
return false;
|
||||
}
|
||||
|
||||
public void Reset()
|
||||
bool TryReturn()
|
||||
{
|
||||
TaskTracker.RemoveTracking(this);
|
||||
core.Reset();
|
||||
innerEnumerator = default;
|
||||
cancellationToken = default;
|
||||
return pool.TryPush(this);
|
||||
}
|
||||
|
||||
~EnumeratorPromise()
|
||||
{
|
||||
if (pool.TryReturn(this))
|
||||
if (TryReturn())
|
||||
{
|
||||
GC.ReRegisterForFinalize(this);
|
||||
}
|
||||
|
||||
@@ -72,14 +72,20 @@ namespace Cysharp.Threading.Tasks
|
||||
public void UnsafeOnCompleted(Action continuation)
|
||||
{
|
||||
Error.ThrowWhenContinuationIsAlreadyRegistered(continuationAction);
|
||||
continuationAction = continuation.AsFuncOfT<AsyncOperationHandle>(); // allocate delegate.
|
||||
continuationAction = PooledDelegate<AsyncOperationHandle>.Create(continuation);
|
||||
handle.Completed += continuationAction;
|
||||
}
|
||||
}
|
||||
|
||||
sealed class AsyncOperationHandleConfiguredSource : IUniTaskSource, IPlayerLoopItem, IPromisePoolItem
|
||||
sealed class AsyncOperationHandleConfiguredSource : IUniTaskSource, IPlayerLoopItem, ITaskPoolNode<AsyncOperationHandleConfiguredSource>
|
||||
{
|
||||
static readonly PromisePool<AsyncOperationHandleConfiguredSource> pool = new PromisePool<AsyncOperationHandleConfiguredSource>();
|
||||
static TaskPool<AsyncOperationHandleConfiguredSource> pool;
|
||||
public AsyncOperationHandleConfiguredSource NextNode { get; set; }
|
||||
|
||||
static AsyncOperationHandleConfiguredSource()
|
||||
{
|
||||
TaskPoolMonitor.RegisterSizeGetter(typeof(AsyncOperationHandleConfiguredSource), () => pool.Size);
|
||||
}
|
||||
|
||||
AsyncOperationHandle handle;
|
||||
IProgress<float> progress;
|
||||
@@ -99,7 +105,10 @@ namespace Cysharp.Threading.Tasks
|
||||
return AutoResetUniTaskCompletionSource.CreateFromCanceled(cancellationToken, out token);
|
||||
}
|
||||
|
||||
var result = pool.TryRent() ?? new AsyncOperationHandleConfiguredSource();
|
||||
if (!pool.TryPop(out var result))
|
||||
{
|
||||
result = new AsyncOperationHandleConfiguredSource();
|
||||
}
|
||||
|
||||
result.handle = handle;
|
||||
result.progress = progress;
|
||||
@@ -117,12 +126,12 @@ namespace Cysharp.Threading.Tasks
|
||||
{
|
||||
try
|
||||
{
|
||||
TaskTracker.RemoveTracking(this);
|
||||
|
||||
core.GetResult(token);
|
||||
}
|
||||
finally
|
||||
{
|
||||
pool.TryReturn(this);
|
||||
TryReturn();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -170,17 +179,19 @@ namespace Cysharp.Threading.Tasks
|
||||
return true;
|
||||
}
|
||||
|
||||
public void Reset()
|
||||
bool TryReturn()
|
||||
{
|
||||
core.Reset();
|
||||
TaskTracker.RemoveTracking(this);
|
||||
handle = default;
|
||||
progress = default;
|
||||
cancellationToken = default;
|
||||
return pool.TryPush(this);
|
||||
}
|
||||
|
||||
~AsyncOperationHandleConfiguredSource()
|
||||
{
|
||||
if (pool.TryReturn(this))
|
||||
if (TryReturn())
|
||||
{
|
||||
GC.ReRegisterForFinalize(this);
|
||||
}
|
||||
@@ -249,14 +260,20 @@ namespace Cysharp.Threading.Tasks
|
||||
public void UnsafeOnCompleted(Action continuation)
|
||||
{
|
||||
Error.ThrowWhenContinuationIsAlreadyRegistered(continuationAction);
|
||||
continuationAction = continuation.AsFuncOfT<AsyncOperationHandle>(); // allocate delegate.
|
||||
continuationAction = PooledDelegate<AsyncOperationHandle>.Create(continuation);
|
||||
handle.CompletedTypeless += continuationAction;
|
||||
}
|
||||
}
|
||||
|
||||
sealed class AsyncOperationHandleConfiguredSource<T> : IUniTaskSource<T>, IPlayerLoopItem, IPromisePoolItem
|
||||
sealed class AsyncOperationHandleConfiguredSource<T> : IUniTaskSource<T>, IPlayerLoopItem, ITaskPoolNode<AsyncOperationHandleConfiguredSource<T>>
|
||||
{
|
||||
static readonly PromisePool<AsyncOperationHandleConfiguredSource<T>> pool = new PromisePool<AsyncOperationHandleConfiguredSource<T>>();
|
||||
static TaskPool<AsyncOperationHandleConfiguredSource<T>> pool;
|
||||
public AsyncOperationHandleConfiguredSource<T> NextNode { get; set; }
|
||||
|
||||
static AsyncOperationHandleConfiguredSource()
|
||||
{
|
||||
TaskPoolMonitor.RegisterSizeGetter(typeof(AsyncOperationHandleConfiguredSource<T>), () => pool.Size);
|
||||
}
|
||||
|
||||
AsyncOperationHandle<T> handle;
|
||||
IProgress<float> progress;
|
||||
@@ -276,7 +293,10 @@ namespace Cysharp.Threading.Tasks
|
||||
return AutoResetUniTaskCompletionSource<T>.CreateFromCanceled(cancellationToken, out token);
|
||||
}
|
||||
|
||||
var result = pool.TryRent() ?? new AsyncOperationHandleConfiguredSource<T>();
|
||||
if (!pool.TryPop(out var result))
|
||||
{
|
||||
result = new AsyncOperationHandleConfiguredSource<T>();
|
||||
}
|
||||
|
||||
result.handle = handle;
|
||||
result.progress = progress;
|
||||
@@ -294,13 +314,11 @@ namespace Cysharp.Threading.Tasks
|
||||
{
|
||||
try
|
||||
{
|
||||
TaskTracker.RemoveTracking(this);
|
||||
|
||||
return core.GetResult(token);
|
||||
}
|
||||
finally
|
||||
{
|
||||
pool.TryReturn(this);
|
||||
TryReturn();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -353,17 +371,19 @@ namespace Cysharp.Threading.Tasks
|
||||
return true;
|
||||
}
|
||||
|
||||
public void Reset()
|
||||
bool TryReturn()
|
||||
{
|
||||
TaskTracker.RemoveTracking(this);
|
||||
core.Reset();
|
||||
handle = default;
|
||||
progress = default;
|
||||
cancellationToken = default;
|
||||
return pool.TryPush(this);
|
||||
}
|
||||
|
||||
~AsyncOperationHandleConfiguredSource()
|
||||
{
|
||||
if (pool.TryReturn(this))
|
||||
if (TryReturn())
|
||||
{
|
||||
GC.ReRegisterForFinalize(this);
|
||||
}
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
using Cysharp.Threading.Tasks.Internal;
|
||||
using DG.Tweening;
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Threading;
|
||||
|
||||
@@ -77,18 +78,26 @@ namespace Cysharp.Threading.Tasks
|
||||
|
||||
public void UnsafeOnCompleted(System.Action continuation)
|
||||
{
|
||||
// convert Action -> TweenCallback allocation.
|
||||
// onKill is called after OnCompleted, both Complete(false/true) and Kill(false/true).
|
||||
tween.onKill = new TweenCallback(continuation);
|
||||
tween.onKill = PooledTweenCallback.Create(continuation);
|
||||
}
|
||||
}
|
||||
|
||||
sealed class TweenConfiguredSource : IUniTaskSource, IPromisePoolItem
|
||||
sealed class TweenConfiguredSource : IUniTaskSource, ITaskPoolNode<TweenConfiguredSource>
|
||||
{
|
||||
static readonly PromisePool<TweenConfiguredSource> pool = new PromisePool<TweenConfiguredSource>();
|
||||
static TaskPool<TweenConfiguredSource> pool;
|
||||
public TweenConfiguredSource NextNode { get; set; }
|
||||
|
||||
static TweenConfiguredSource()
|
||||
{
|
||||
TaskPoolMonitor.RegisterSizeGetter(typeof(TweenConfiguredSource), () => pool.Size);
|
||||
}
|
||||
|
||||
static readonly Action<object> CancellationCallbackDelegate = CancellationCallback;
|
||||
static readonly TweenCallback EmptyTweenCallback = () => { };
|
||||
|
||||
readonly TweenCallback onKillDelegate;
|
||||
|
||||
Tween tween;
|
||||
TweenCancelBehaviour cancelBehaviour;
|
||||
CancellationToken cancellationToken;
|
||||
@@ -99,7 +108,7 @@ namespace Cysharp.Threading.Tasks
|
||||
|
||||
TweenConfiguredSource()
|
||||
{
|
||||
|
||||
onKillDelegate = OnKill;
|
||||
}
|
||||
|
||||
public static IUniTaskSource Create(Tween tween, TweenCancelBehaviour cancelBehaviour, CancellationToken cancellationToken, out short token)
|
||||
@@ -109,7 +118,10 @@ namespace Cysharp.Threading.Tasks
|
||||
return AutoResetUniTaskCompletionSource.CreateFromCanceled(cancellationToken, out token);
|
||||
}
|
||||
|
||||
var result = pool.TryRent() ?? new TweenConfiguredSource();
|
||||
if (!pool.TryPop(out var result))
|
||||
{
|
||||
result = new TweenConfiguredSource();
|
||||
}
|
||||
|
||||
result.tween = tween;
|
||||
result.cancelBehaviour = cancelBehaviour;
|
||||
@@ -130,8 +142,7 @@ namespace Cysharp.Threading.Tasks
|
||||
cancellationTokenRegistration = cancellationToken.RegisterWithoutCaptureExecutionContext(CancellationCallbackDelegate, this);
|
||||
}
|
||||
|
||||
// allocate delegate.
|
||||
tween.OnKill(new TweenCallback(OnKill));
|
||||
tween.OnKill(onKillDelegate);
|
||||
}
|
||||
|
||||
void OnKill()
|
||||
@@ -193,12 +204,11 @@ namespace Cysharp.Threading.Tasks
|
||||
{
|
||||
try
|
||||
{
|
||||
TaskTracker.RemoveTracking(this);
|
||||
core.GetResult(token);
|
||||
}
|
||||
finally
|
||||
{
|
||||
pool.TryReturn(this);
|
||||
TryReturn();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -218,22 +228,63 @@ namespace Cysharp.Threading.Tasks
|
||||
core.OnCompleted(continuation, state, token);
|
||||
}
|
||||
|
||||
public void Reset()
|
||||
bool TryReturn()
|
||||
{
|
||||
TaskTracker.RemoveTracking(this);
|
||||
core.Reset();
|
||||
tween = default;
|
||||
cancellationToken = default;
|
||||
return pool.TryPush(this);
|
||||
}
|
||||
|
||||
~TweenConfiguredSource()
|
||||
{
|
||||
if (pool.TryReturn(this))
|
||||
if (TryReturn())
|
||||
{
|
||||
GC.ReRegisterForFinalize(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
sealed class PooledTweenCallback
|
||||
{
|
||||
static readonly ConcurrentQueue<PooledTweenCallback> pool = new ConcurrentQueue<PooledTweenCallback>();
|
||||
|
||||
readonly TweenCallback runDelegate;
|
||||
|
||||
Action continuation;
|
||||
|
||||
|
||||
PooledTweenCallback()
|
||||
{
|
||||
runDelegate = Run;
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static TweenCallback Create(Action continuation)
|
||||
{
|
||||
if (!pool.TryDequeue(out var item))
|
||||
{
|
||||
item = new PooledTweenCallback();
|
||||
}
|
||||
|
||||
item.continuation = continuation;
|
||||
return item.runDelegate;
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
void Run()
|
||||
{
|
||||
var call = continuation;
|
||||
continuation = null;
|
||||
if (call != null)
|
||||
{
|
||||
pool.Enqueue(this);
|
||||
call.Invoke();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
@@ -0,0 +1,49 @@
|
||||
using System;
|
||||
using System.Runtime.CompilerServices;
|
||||
|
||||
namespace Cysharp.Threading.Tasks.Internal
|
||||
{
|
||||
internal sealed class PooledDelegate<T> : ITaskPoolNode<PooledDelegate<T>>
|
||||
{
|
||||
static TaskPool<PooledDelegate<T>> pool;
|
||||
|
||||
public PooledDelegate<T> NextNode { get; set; }
|
||||
|
||||
static PooledDelegate()
|
||||
{
|
||||
TaskPoolMonitor.RegisterSizeGetter(typeof(PooledDelegate<T>), () => pool.Size);
|
||||
}
|
||||
|
||||
readonly Action<T> runDelegate;
|
||||
Action continuation;
|
||||
|
||||
PooledDelegate()
|
||||
{
|
||||
runDelegate = Run;
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static Action<T> Create(Action continuation)
|
||||
{
|
||||
if (!pool.TryPop(out var item))
|
||||
{
|
||||
item = new PooledDelegate<T>();
|
||||
}
|
||||
|
||||
item.continuation = continuation;
|
||||
return item.runDelegate;
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
void Run(T _)
|
||||
{
|
||||
var call = continuation;
|
||||
continuation = null;
|
||||
if (call != null)
|
||||
{
|
||||
pool.TryPush(this);
|
||||
call.Invoke();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 8932579438742fa40b010edd412dbfba
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -1,55 +0,0 @@
|
||||
using System.Collections.Concurrent;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Threading;
|
||||
|
||||
namespace Cysharp.Threading.Tasks.Internal
|
||||
{
|
||||
// public, allow to user create custom operator with pool.
|
||||
|
||||
public interface IPromisePoolItem
|
||||
{
|
||||
void Reset();
|
||||
}
|
||||
|
||||
public class PromisePool<T>
|
||||
where T : class, IPromisePoolItem
|
||||
{
|
||||
int count = 0;
|
||||
readonly ConcurrentQueue<T> queue = new ConcurrentQueue<T>();
|
||||
readonly int maxSize;
|
||||
|
||||
public PromisePool(int maxSize = 256)
|
||||
{
|
||||
this.maxSize = maxSize;
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public T TryRent()
|
||||
{
|
||||
if (queue.TryDequeue(out var value))
|
||||
{
|
||||
Interlocked.Decrement(ref count);
|
||||
return value;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public bool TryReturn(T value)
|
||||
{
|
||||
value.Reset(); // reset when return.
|
||||
|
||||
if (count < maxSize)
|
||||
{
|
||||
queue.Enqueue(value);
|
||||
Interlocked.Increment(ref count);
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
119
src/UniTask/Assets/Plugins/UniTask/Runtime/Internal/TaskPool.cs
Normal file
119
src/UniTask/Assets/Plugins/UniTask/Runtime/Internal/TaskPool.cs
Normal file
@@ -0,0 +1,119 @@
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Threading;
|
||||
|
||||
namespace Cysharp.Threading.Tasks.Internal
|
||||
{
|
||||
// internaly used but public, allow to user create custom operator with pooling.
|
||||
|
||||
public static class TaskPool
|
||||
{
|
||||
internal static int MaxPoolSize;
|
||||
|
||||
static TaskPool()
|
||||
{
|
||||
try
|
||||
{
|
||||
var value = Environment.GetEnvironmentVariable("UNITASK_MAX_POOLSIZE");
|
||||
if (value != null)
|
||||
{
|
||||
if (int.TryParse(value, out var size))
|
||||
{
|
||||
MaxPoolSize = size;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
catch { }
|
||||
|
||||
MaxPoolSize = int.MaxValue;
|
||||
}
|
||||
|
||||
public static void SetMaxPoolSize(int maxPoolSize)
|
||||
{
|
||||
MaxPoolSize = maxPoolSize;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public interface ITaskPoolNode<T>
|
||||
{
|
||||
T NextNode { get; set; }
|
||||
}
|
||||
|
||||
// mutable struct, don't mark readonly.
|
||||
[StructLayout(LayoutKind.Auto)]
|
||||
public struct TaskPool<T>
|
||||
where T : class, ITaskPoolNode<T>
|
||||
{
|
||||
int gate;
|
||||
int size;
|
||||
T root;
|
||||
|
||||
public int Size => size;
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public bool TryPop(out T result)
|
||||
{
|
||||
if (Interlocked.CompareExchange(ref gate, 1, 0) == 0)
|
||||
{
|
||||
var v = root;
|
||||
if (!(v is null))
|
||||
{
|
||||
root = v.NextNode;
|
||||
v.NextNode = null;
|
||||
size--;
|
||||
result = v;
|
||||
Volatile.Write(ref gate, 0);
|
||||
return true;
|
||||
}
|
||||
|
||||
Volatile.Write(ref gate, 0);
|
||||
}
|
||||
result = default;
|
||||
return false;
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public bool TryPush(T item)
|
||||
{
|
||||
if (Interlocked.CompareExchange(ref gate, 1, 0) == 0)
|
||||
{
|
||||
if (size < TaskPool.MaxPoolSize)
|
||||
{
|
||||
item.NextNode = root;
|
||||
root = item;
|
||||
size++;
|
||||
Volatile.Write(ref gate, 0);
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
Volatile.Write(ref gate, 0);
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public static class TaskPoolMonitor
|
||||
{
|
||||
static ConcurrentDictionary<Type, Func<int>> sizes = new ConcurrentDictionary<Type, Func<int>>();
|
||||
|
||||
public static IEnumerable<(Type, int)> GetCacheSizeInfo()
|
||||
{
|
||||
foreach (var item in sizes)
|
||||
{
|
||||
yield return (item.Key, item.Value());
|
||||
}
|
||||
}
|
||||
|
||||
public static void RegisterSizeGetter(Type type, Func<int> getSize)
|
||||
{
|
||||
sizes[type] = getSize;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 19f4e6575150765449cc99f25f06f25f
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -3,6 +3,7 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
using Cysharp.Threading.Tasks.Internal;
|
||||
|
||||
@@ -103,16 +104,11 @@ namespace Cysharp.Threading.Tasks
|
||||
{
|
||||
for (int i = 0; i < count; i++)
|
||||
{
|
||||
string typeName = null;
|
||||
var keyType = listPool[i].Key.GetType();
|
||||
if (keyType.IsNested)
|
||||
{
|
||||
typeName = keyType.DeclaringType.Name + "." + keyType.Name;
|
||||
}
|
||||
else
|
||||
{
|
||||
typeName = keyType.Name;
|
||||
}
|
||||
|
||||
var sb = new StringBuilder();
|
||||
TypeBeautify(keyType, sb);
|
||||
var typeName = sb.ToString();
|
||||
|
||||
action(listPool[i].Value.trackingId, typeName, listPool[i].Key.UnsafeGetStatus(), listPool[i].Value.addTime, listPool[i].Value.stackTrace);
|
||||
listPool[i] = new KeyValuePair<IUniTaskSource, (int trackingId, DateTime addTime, string stackTrace)>(null, (0, default(DateTime), null)); // clear
|
||||
@@ -125,6 +121,31 @@ namespace Cysharp.Threading.Tasks
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void TypeBeautify(Type type, StringBuilder sb)
|
||||
{
|
||||
if (type.IsNested)
|
||||
{
|
||||
TypeBeautify(type.DeclaringType, sb);
|
||||
sb.Append(".");
|
||||
}
|
||||
|
||||
if (type.IsGenericType)
|
||||
{
|
||||
var genericsStart = type.Name.IndexOf("`");
|
||||
sb.Append(type.Name.Substring(0, genericsStart));
|
||||
sb.Append("<");
|
||||
foreach (var item in type.GetGenericArguments())
|
||||
{
|
||||
TypeBeautify(item, sb);
|
||||
}
|
||||
sb.Append(">");
|
||||
}
|
||||
else
|
||||
{
|
||||
sb.Append(type.Name);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -56,9 +56,15 @@ namespace Cysharp.Threading.Tasks
|
||||
: new UniTask(DelayPromise.Create(delayTimeSpan, delayTiming, cancellationToken, out token), token);
|
||||
}
|
||||
|
||||
sealed class YieldPromise : IUniTaskSource, IPlayerLoopItem, IPromisePoolItem
|
||||
sealed class YieldPromise : IUniTaskSource, IPlayerLoopItem, ITaskPoolNode<YieldPromise>
|
||||
{
|
||||
static readonly PromisePool<YieldPromise> pool = new PromisePool<YieldPromise>();
|
||||
static TaskPool<YieldPromise> pool;
|
||||
public YieldPromise NextNode { get; set; }
|
||||
|
||||
static YieldPromise()
|
||||
{
|
||||
TaskPoolMonitor.RegisterSizeGetter(typeof(YieldPromise), () => pool.Size);
|
||||
}
|
||||
|
||||
CancellationToken cancellationToken;
|
||||
UniTaskCompletionSourceCore<object> core;
|
||||
@@ -74,7 +80,11 @@ namespace Cysharp.Threading.Tasks
|
||||
return AutoResetUniTaskCompletionSource.CreateFromCanceled(cancellationToken, out token);
|
||||
}
|
||||
|
||||
var result = pool.TryRent() ?? new YieldPromise();
|
||||
if (!pool.TryPop(out var result))
|
||||
{
|
||||
result = new YieldPromise();
|
||||
}
|
||||
|
||||
|
||||
result.cancellationToken = cancellationToken;
|
||||
|
||||
@@ -90,12 +100,11 @@ namespace Cysharp.Threading.Tasks
|
||||
{
|
||||
try
|
||||
{
|
||||
TaskTracker.RemoveTracking(this);
|
||||
core.GetResult(token);
|
||||
}
|
||||
finally
|
||||
{
|
||||
pool.TryReturn(this);
|
||||
TryReturn();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -126,24 +135,32 @@ namespace Cysharp.Threading.Tasks
|
||||
return false;
|
||||
}
|
||||
|
||||
public void Reset()
|
||||
bool TryReturn()
|
||||
{
|
||||
TaskTracker.RemoveTracking(this);
|
||||
core.Reset();
|
||||
cancellationToken = default;
|
||||
return pool.TryPush(this);
|
||||
}
|
||||
|
||||
~YieldPromise()
|
||||
{
|
||||
if (pool.TryReturn(this))
|
||||
if (TryReturn())
|
||||
{
|
||||
GC.ReRegisterForFinalize(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
sealed class DelayFramePromise : IUniTaskSource, IPlayerLoopItem, IPromisePoolItem
|
||||
sealed class DelayFramePromise : IUniTaskSource, IPlayerLoopItem, ITaskPoolNode<DelayFramePromise>
|
||||
{
|
||||
static readonly PromisePool<DelayFramePromise> pool = new PromisePool<DelayFramePromise>();
|
||||
static TaskPool<DelayFramePromise> pool;
|
||||
public DelayFramePromise NextNode { get; set; }
|
||||
|
||||
static DelayFramePromise()
|
||||
{
|
||||
TaskPoolMonitor.RegisterSizeGetter(typeof(DelayFramePromise), () => pool.Size);
|
||||
}
|
||||
|
||||
int delayFrameCount;
|
||||
CancellationToken cancellationToken;
|
||||
@@ -162,7 +179,10 @@ namespace Cysharp.Threading.Tasks
|
||||
return AutoResetUniTaskCompletionSource.CreateFromCanceled(cancellationToken, out token);
|
||||
}
|
||||
|
||||
var result = pool.TryRent() ?? new DelayFramePromise();
|
||||
if (!pool.TryPop(out var result))
|
||||
{
|
||||
result = new DelayFramePromise();
|
||||
}
|
||||
|
||||
result.delayFrameCount = delayFrameCount;
|
||||
result.cancellationToken = cancellationToken;
|
||||
@@ -179,12 +199,11 @@ namespace Cysharp.Threading.Tasks
|
||||
{
|
||||
try
|
||||
{
|
||||
TaskTracker.RemoveTracking(this);
|
||||
core.GetResult(token);
|
||||
}
|
||||
finally
|
||||
{
|
||||
pool.TryReturn(this);
|
||||
TryReturn();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -221,26 +240,34 @@ namespace Cysharp.Threading.Tasks
|
||||
return true;
|
||||
}
|
||||
|
||||
public void Reset()
|
||||
bool TryReturn()
|
||||
{
|
||||
TaskTracker.RemoveTracking(this);
|
||||
core.Reset();
|
||||
currentFrameCount = default;
|
||||
delayFrameCount = default;
|
||||
cancellationToken = default;
|
||||
return pool.TryPush(this);
|
||||
}
|
||||
|
||||
~DelayFramePromise()
|
||||
{
|
||||
if (pool.TryReturn(this))
|
||||
if (TryReturn())
|
||||
{
|
||||
GC.ReRegisterForFinalize(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
sealed class DelayPromise : IUniTaskSource, IPlayerLoopItem, IPromisePoolItem
|
||||
sealed class DelayPromise : IUniTaskSource, IPlayerLoopItem, ITaskPoolNode<DelayPromise>
|
||||
{
|
||||
static readonly PromisePool<DelayPromise> pool = new PromisePool<DelayPromise>();
|
||||
static TaskPool<DelayPromise> pool;
|
||||
public DelayPromise NextNode { get; set; }
|
||||
|
||||
static DelayPromise()
|
||||
{
|
||||
TaskPoolMonitor.RegisterSizeGetter(typeof(DelayPromise), () => pool.Size);
|
||||
}
|
||||
|
||||
float delayFrameTimeSpan;
|
||||
float elapsed;
|
||||
@@ -259,7 +286,10 @@ namespace Cysharp.Threading.Tasks
|
||||
return AutoResetUniTaskCompletionSource.CreateFromCanceled(cancellationToken, out token);
|
||||
}
|
||||
|
||||
var result = pool.TryRent() ?? new DelayPromise();
|
||||
if (!pool.TryPop(out var result))
|
||||
{
|
||||
result = new DelayPromise();
|
||||
}
|
||||
|
||||
result.elapsed = 0.0f;
|
||||
result.delayFrameTimeSpan = (float)delayFrameTimeSpan.TotalSeconds;
|
||||
@@ -277,12 +307,11 @@ namespace Cysharp.Threading.Tasks
|
||||
{
|
||||
try
|
||||
{
|
||||
TaskTracker.RemoveTracking(this);
|
||||
core.GetResult(token);
|
||||
}
|
||||
finally
|
||||
{
|
||||
pool.TryReturn(this);
|
||||
TryReturn();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -319,26 +348,34 @@ namespace Cysharp.Threading.Tasks
|
||||
return true;
|
||||
}
|
||||
|
||||
public void Reset()
|
||||
bool TryReturn()
|
||||
{
|
||||
TaskTracker.RemoveTracking(this);
|
||||
core.Reset();
|
||||
delayFrameTimeSpan = default;
|
||||
elapsed = default;
|
||||
cancellationToken = default;
|
||||
return pool.TryPush(this);
|
||||
}
|
||||
|
||||
~DelayPromise()
|
||||
{
|
||||
if (pool.TryReturn(this))
|
||||
if (TryReturn())
|
||||
{
|
||||
GC.ReRegisterForFinalize(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
sealed class DelayIgnoreTimeScalePromise : IUniTaskSource, IPlayerLoopItem, IPromisePoolItem
|
||||
sealed class DelayIgnoreTimeScalePromise : IUniTaskSource, IPlayerLoopItem, ITaskPoolNode<DelayIgnoreTimeScalePromise>
|
||||
{
|
||||
static readonly PromisePool<DelayIgnoreTimeScalePromise> pool = new PromisePool<DelayIgnoreTimeScalePromise>();
|
||||
static TaskPool<DelayIgnoreTimeScalePromise> pool;
|
||||
public DelayIgnoreTimeScalePromise NextNode { get; set; }
|
||||
|
||||
static DelayIgnoreTimeScalePromise()
|
||||
{
|
||||
TaskPoolMonitor.RegisterSizeGetter(typeof(DelayIgnoreTimeScalePromise), () => pool.Size);
|
||||
}
|
||||
|
||||
float delayFrameTimeSpan;
|
||||
float elapsed;
|
||||
@@ -357,7 +394,10 @@ namespace Cysharp.Threading.Tasks
|
||||
return AutoResetUniTaskCompletionSource.CreateFromCanceled(cancellationToken, out token);
|
||||
}
|
||||
|
||||
var result = pool.TryRent() ?? new DelayIgnoreTimeScalePromise();
|
||||
if (!pool.TryPop(out var result))
|
||||
{
|
||||
result = new DelayIgnoreTimeScalePromise();
|
||||
}
|
||||
|
||||
result.elapsed = 0.0f;
|
||||
result.delayFrameTimeSpan = (float)delayFrameTimeSpan.TotalSeconds;
|
||||
@@ -375,12 +415,11 @@ namespace Cysharp.Threading.Tasks
|
||||
{
|
||||
try
|
||||
{
|
||||
TaskTracker.RemoveTracking(this);
|
||||
core.GetResult(token);
|
||||
}
|
||||
finally
|
||||
{
|
||||
pool.TryReturn(this);
|
||||
TryReturn();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -417,17 +456,19 @@ namespace Cysharp.Threading.Tasks
|
||||
return true;
|
||||
}
|
||||
|
||||
public void Reset()
|
||||
bool TryReturn()
|
||||
{
|
||||
TaskTracker.RemoveTracking(this);
|
||||
core.Reset();
|
||||
delayFrameTimeSpan = default;
|
||||
elapsed = default;
|
||||
cancellationToken = default;
|
||||
return pool.TryPush(this);
|
||||
}
|
||||
|
||||
~DelayIgnoreTimeScalePromise()
|
||||
{
|
||||
if (pool.TryReturn(this))
|
||||
if (TryReturn())
|
||||
{
|
||||
GC.ReRegisterForFinalize(this);
|
||||
}
|
||||
|
||||
@@ -35,9 +35,15 @@ namespace Cysharp.Threading.Tasks
|
||||
: WaitUntilValueChangedStandardObjectPromise<T, U>.Create(target, monitorFunction, equalityComparer, monitorTiming, cancellationToken, out token), token);
|
||||
}
|
||||
|
||||
sealed class WaitUntilPromise : IUniTaskSource, IPlayerLoopItem, IPromisePoolItem
|
||||
sealed class WaitUntilPromise : IUniTaskSource, IPlayerLoopItem, ITaskPoolNode<WaitUntilPromise>
|
||||
{
|
||||
static readonly PromisePool<WaitUntilPromise> pool = new PromisePool<WaitUntilPromise>();
|
||||
static TaskPool<WaitUntilPromise> pool;
|
||||
public WaitUntilPromise NextNode { get; set; }
|
||||
|
||||
static WaitUntilPromise()
|
||||
{
|
||||
TaskPoolMonitor.RegisterSizeGetter(typeof(WaitUntilPromise), () => pool.Size);
|
||||
}
|
||||
|
||||
Func<bool> predicate;
|
||||
CancellationToken cancellationToken;
|
||||
@@ -55,7 +61,10 @@ namespace Cysharp.Threading.Tasks
|
||||
return AutoResetUniTaskCompletionSource.CreateFromCanceled(cancellationToken, out token);
|
||||
}
|
||||
|
||||
var result = pool.TryRent() ?? new WaitUntilPromise();
|
||||
if (!pool.TryPop(out var result))
|
||||
{
|
||||
result = new WaitUntilPromise();
|
||||
}
|
||||
|
||||
result.predicate = predicate;
|
||||
result.cancellationToken = cancellationToken;
|
||||
@@ -72,12 +81,11 @@ namespace Cysharp.Threading.Tasks
|
||||
{
|
||||
try
|
||||
{
|
||||
TaskTracker.RemoveTracking(this);
|
||||
core.GetResult(token);
|
||||
}
|
||||
finally
|
||||
{
|
||||
pool.TryReturn(this);
|
||||
TryReturn();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -121,25 +129,33 @@ namespace Cysharp.Threading.Tasks
|
||||
return false;
|
||||
}
|
||||
|
||||
public void Reset()
|
||||
bool TryReturn()
|
||||
{
|
||||
TaskTracker.RemoveTracking(this);
|
||||
core.Reset();
|
||||
predicate = default;
|
||||
cancellationToken = default;
|
||||
return pool.TryPush(this);
|
||||
}
|
||||
|
||||
~WaitUntilPromise()
|
||||
{
|
||||
if (pool.TryReturn(this))
|
||||
if (TryReturn())
|
||||
{
|
||||
GC.ReRegisterForFinalize(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
sealed class WaitWhilePromise : IUniTaskSource, IPlayerLoopItem, IPromisePoolItem
|
||||
sealed class WaitWhilePromise : IUniTaskSource, IPlayerLoopItem, ITaskPoolNode<WaitWhilePromise>
|
||||
{
|
||||
static readonly PromisePool<WaitWhilePromise> pool = new PromisePool<WaitWhilePromise>();
|
||||
static TaskPool<WaitWhilePromise> pool;
|
||||
public WaitWhilePromise NextNode { get; set; }
|
||||
|
||||
static WaitWhilePromise()
|
||||
{
|
||||
TaskPoolMonitor.RegisterSizeGetter(typeof(WaitWhilePromise), () => pool.Size);
|
||||
}
|
||||
|
||||
Func<bool> predicate;
|
||||
CancellationToken cancellationToken;
|
||||
@@ -157,7 +173,10 @@ namespace Cysharp.Threading.Tasks
|
||||
return AutoResetUniTaskCompletionSource.CreateFromCanceled(cancellationToken, out token);
|
||||
}
|
||||
|
||||
var result = pool.TryRent() ?? new WaitWhilePromise();
|
||||
if (!pool.TryPop(out var result))
|
||||
{
|
||||
result = new WaitWhilePromise();
|
||||
}
|
||||
|
||||
result.predicate = predicate;
|
||||
result.cancellationToken = cancellationToken;
|
||||
@@ -174,12 +193,11 @@ namespace Cysharp.Threading.Tasks
|
||||
{
|
||||
try
|
||||
{
|
||||
TaskTracker.RemoveTracking(this);
|
||||
core.GetResult(token);
|
||||
}
|
||||
finally
|
||||
{
|
||||
pool.TryReturn(this);
|
||||
TryReturn();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -223,25 +241,33 @@ namespace Cysharp.Threading.Tasks
|
||||
return false;
|
||||
}
|
||||
|
||||
public void Reset()
|
||||
bool TryReturn()
|
||||
{
|
||||
TaskTracker.RemoveTracking(this);
|
||||
core.Reset();
|
||||
predicate = default;
|
||||
cancellationToken = default;
|
||||
return pool.TryPush(this);
|
||||
}
|
||||
|
||||
~WaitWhilePromise()
|
||||
{
|
||||
if (pool.TryReturn(this))
|
||||
if (TryReturn())
|
||||
{
|
||||
GC.ReRegisterForFinalize(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
sealed class WaitUntilCanceledPromise : IUniTaskSource, IPlayerLoopItem, IPromisePoolItem
|
||||
sealed class WaitUntilCanceledPromise : IUniTaskSource, IPlayerLoopItem, ITaskPoolNode<WaitUntilCanceledPromise>
|
||||
{
|
||||
static readonly PromisePool<WaitUntilCanceledPromise> pool = new PromisePool<WaitUntilCanceledPromise>();
|
||||
static TaskPool<WaitUntilCanceledPromise> pool;
|
||||
public WaitUntilCanceledPromise NextNode { get; set; }
|
||||
|
||||
static WaitUntilCanceledPromise()
|
||||
{
|
||||
TaskPoolMonitor.RegisterSizeGetter(typeof(WaitUntilCanceledPromise), () => pool.Size);
|
||||
}
|
||||
|
||||
CancellationToken cancellationToken;
|
||||
|
||||
@@ -258,7 +284,10 @@ namespace Cysharp.Threading.Tasks
|
||||
return AutoResetUniTaskCompletionSource.CreateFromCanceled(cancellationToken, out token);
|
||||
}
|
||||
|
||||
var result = pool.TryRent() ?? new WaitUntilCanceledPromise();
|
||||
if (!pool.TryPop(out var result))
|
||||
{
|
||||
result = new WaitUntilCanceledPromise();
|
||||
}
|
||||
|
||||
result.cancellationToken = cancellationToken;
|
||||
|
||||
@@ -274,12 +303,11 @@ namespace Cysharp.Threading.Tasks
|
||||
{
|
||||
try
|
||||
{
|
||||
TaskTracker.RemoveTracking(this);
|
||||
core.GetResult(token);
|
||||
}
|
||||
finally
|
||||
{
|
||||
pool.TryReturn(this);
|
||||
TryReturn();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -309,15 +337,17 @@ namespace Cysharp.Threading.Tasks
|
||||
return true;
|
||||
}
|
||||
|
||||
public void Reset()
|
||||
bool TryReturn()
|
||||
{
|
||||
TaskTracker.RemoveTracking(this);
|
||||
core.Reset();
|
||||
cancellationToken = default;
|
||||
return pool.TryPush(this);
|
||||
}
|
||||
|
||||
~WaitUntilCanceledPromise()
|
||||
{
|
||||
if (pool.TryReturn(this))
|
||||
if (TryReturn())
|
||||
{
|
||||
GC.ReRegisterForFinalize(this);
|
||||
}
|
||||
@@ -325,9 +355,15 @@ namespace Cysharp.Threading.Tasks
|
||||
}
|
||||
|
||||
// where T : UnityEngine.Object, can not add constraint
|
||||
sealed class WaitUntilValueChangedUnityObjectPromise<T, U> : IUniTaskSource<U>, IPlayerLoopItem, IPromisePoolItem
|
||||
sealed class WaitUntilValueChangedUnityObjectPromise<T, U> : IUniTaskSource<U>, IPlayerLoopItem, ITaskPoolNode<WaitUntilValueChangedUnityObjectPromise<T, U>>
|
||||
{
|
||||
static readonly PromisePool<WaitUntilValueChangedUnityObjectPromise<T, U>> pool = new PromisePool<WaitUntilValueChangedUnityObjectPromise<T, U>>();
|
||||
static TaskPool<WaitUntilValueChangedUnityObjectPromise<T, U>> pool;
|
||||
public WaitUntilValueChangedUnityObjectPromise<T, U> NextNode { get; set; }
|
||||
|
||||
static WaitUntilValueChangedUnityObjectPromise()
|
||||
{
|
||||
TaskPoolMonitor.RegisterSizeGetter(typeof(WaitUntilValueChangedUnityObjectPromise<T, U>), () => pool.Size);
|
||||
}
|
||||
|
||||
T target;
|
||||
UnityEngine.Object targetAsUnityObject;
|
||||
@@ -349,7 +385,10 @@ namespace Cysharp.Threading.Tasks
|
||||
return AutoResetUniTaskCompletionSource<U>.CreateFromCanceled(cancellationToken, out token);
|
||||
}
|
||||
|
||||
var result = pool.TryRent() ?? new WaitUntilValueChangedUnityObjectPromise<T, U>();
|
||||
if (!pool.TryPop(out var result))
|
||||
{
|
||||
result = new WaitUntilValueChangedUnityObjectPromise<T, U>();
|
||||
}
|
||||
|
||||
result.target = target;
|
||||
result.targetAsUnityObject = target as UnityEngine.Object;
|
||||
@@ -370,12 +409,11 @@ namespace Cysharp.Threading.Tasks
|
||||
{
|
||||
try
|
||||
{
|
||||
TaskTracker.RemoveTracking(this);
|
||||
return core.GetResult(token);
|
||||
}
|
||||
finally
|
||||
{
|
||||
pool.TryReturn(this);
|
||||
TryReturn();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -426,29 +464,37 @@ namespace Cysharp.Threading.Tasks
|
||||
return false;
|
||||
}
|
||||
|
||||
public void Reset()
|
||||
bool TryReturn()
|
||||
{
|
||||
TaskTracker.RemoveTracking(this);
|
||||
core.Reset();
|
||||
target = default;
|
||||
currentValue = default;
|
||||
monitorFunction = default;
|
||||
equalityComparer = default;
|
||||
cancellationToken = default;
|
||||
return pool.TryPush(this);
|
||||
}
|
||||
|
||||
~WaitUntilValueChangedUnityObjectPromise()
|
||||
{
|
||||
if (pool.TryReturn(this))
|
||||
if (TryReturn())
|
||||
{
|
||||
GC.ReRegisterForFinalize(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
sealed class WaitUntilValueChangedStandardObjectPromise<T, U> : IUniTaskSource<U>, IPlayerLoopItem, IPromisePoolItem
|
||||
sealed class WaitUntilValueChangedStandardObjectPromise<T, U> : IUniTaskSource<U>, IPlayerLoopItem, ITaskPoolNode<WaitUntilValueChangedStandardObjectPromise<T, U>>
|
||||
where T : class
|
||||
{
|
||||
static readonly PromisePool<WaitUntilValueChangedStandardObjectPromise<T, U>> pool = new PromisePool<WaitUntilValueChangedStandardObjectPromise<T, U>>();
|
||||
static TaskPool<WaitUntilValueChangedStandardObjectPromise<T, U>> pool;
|
||||
public WaitUntilValueChangedStandardObjectPromise<T, U> NextNode { get; set; }
|
||||
|
||||
static WaitUntilValueChangedStandardObjectPromise()
|
||||
{
|
||||
TaskPoolMonitor.RegisterSizeGetter(typeof(WaitUntilValueChangedStandardObjectPromise<T, U>), () => pool.Size);
|
||||
}
|
||||
|
||||
WeakReference<T> target;
|
||||
U currentValue;
|
||||
@@ -469,7 +515,10 @@ namespace Cysharp.Threading.Tasks
|
||||
return AutoResetUniTaskCompletionSource<U>.CreateFromCanceled(cancellationToken, out token);
|
||||
}
|
||||
|
||||
var result = pool.TryRent() ?? new WaitUntilValueChangedStandardObjectPromise<T, U>();
|
||||
if (!pool.TryPop(out var result))
|
||||
{
|
||||
result = new WaitUntilValueChangedStandardObjectPromise<T, U>();
|
||||
}
|
||||
|
||||
result.target = new WeakReference<T>(target, false); // wrap in WeakReference.
|
||||
result.monitorFunction = monitorFunction;
|
||||
@@ -489,12 +538,11 @@ namespace Cysharp.Threading.Tasks
|
||||
{
|
||||
try
|
||||
{
|
||||
TaskTracker.RemoveTracking(this);
|
||||
return core.GetResult(token);
|
||||
}
|
||||
finally
|
||||
{
|
||||
pool.TryReturn(this);
|
||||
TryReturn();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -545,19 +593,21 @@ namespace Cysharp.Threading.Tasks
|
||||
return false;
|
||||
}
|
||||
|
||||
public void Reset()
|
||||
bool TryReturn()
|
||||
{
|
||||
TaskTracker.RemoveTracking(this);
|
||||
core.Reset();
|
||||
target = default;
|
||||
currentValue = default;
|
||||
monitorFunction = default;
|
||||
equalityComparer = default;
|
||||
cancellationToken = default;
|
||||
return pool.TryPush(this);
|
||||
}
|
||||
|
||||
~WaitUntilValueChangedStandardObjectPromise()
|
||||
{
|
||||
if (pool.TryReturn(this))
|
||||
if (TryReturn())
|
||||
{
|
||||
GC.ReRegisterForFinalize(this);
|
||||
}
|
||||
|
||||
@@ -12,10 +12,11 @@ namespace Cysharp.Threading.Tasks
|
||||
{
|
||||
internal static class AwaiterActions
|
||||
{
|
||||
internal static readonly Action<object> InvokeActionDelegate = InvokeAction;
|
||||
internal static readonly Action<object> InvokeContinuationDelegate = Continuation;
|
||||
|
||||
[DebuggerHidden]
|
||||
static void InvokeAction(object state)
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
static void Continuation(object state)
|
||||
{
|
||||
((Action)state).Invoke();
|
||||
}
|
||||
@@ -312,7 +313,7 @@ namespace Cysharp.Threading.Tasks
|
||||
}
|
||||
else
|
||||
{
|
||||
task.source.OnCompleted(AwaiterActions.InvokeActionDelegate, continuation, task.token);
|
||||
task.source.OnCompleted(AwaiterActions.InvokeContinuationDelegate, continuation, task.token);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -326,7 +327,7 @@ namespace Cysharp.Threading.Tasks
|
||||
}
|
||||
else
|
||||
{
|
||||
task.source.OnCompleted(AwaiterActions.InvokeActionDelegate, continuation, task.token);
|
||||
task.source.OnCompleted(AwaiterActions.InvokeContinuationDelegate, continuation, task.token);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -650,7 +651,7 @@ namespace Cysharp.Threading.Tasks
|
||||
}
|
||||
else
|
||||
{
|
||||
s.OnCompleted(AwaiterActions.InvokeActionDelegate, continuation, task.token);
|
||||
s.OnCompleted(AwaiterActions.InvokeContinuationDelegate, continuation, task.token);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -665,7 +666,7 @@ namespace Cysharp.Threading.Tasks
|
||||
}
|
||||
else
|
||||
{
|
||||
s.OnCompleted(AwaiterActions.InvokeActionDelegate, continuation, task.token);
|
||||
s.OnCompleted(AwaiterActions.InvokeContinuationDelegate, continuation, task.token);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -375,9 +375,15 @@ namespace Cysharp.Threading.Tasks
|
||||
}
|
||||
}
|
||||
|
||||
public class AutoResetUniTaskCompletionSource : IUniTaskSource, IPromisePoolItem, IPromise
|
||||
public class AutoResetUniTaskCompletionSource : IUniTaskSource, ITaskPoolNode<AutoResetUniTaskCompletionSource>, IPromise
|
||||
{
|
||||
static readonly PromisePool<AutoResetUniTaskCompletionSource> pool = new PromisePool<AutoResetUniTaskCompletionSource>();
|
||||
static TaskPool<AutoResetUniTaskCompletionSource> pool;
|
||||
public AutoResetUniTaskCompletionSource NextNode { get; set; }
|
||||
|
||||
static AutoResetUniTaskCompletionSource()
|
||||
{
|
||||
TaskPoolMonitor.RegisterSizeGetter(typeof(AutoResetUniTaskCompletionSource), () => pool.Size);
|
||||
}
|
||||
|
||||
UniTaskCompletionSourceCore<AsyncUnit> core;
|
||||
|
||||
@@ -388,9 +394,12 @@ namespace Cysharp.Threading.Tasks
|
||||
[DebuggerHidden]
|
||||
public static AutoResetUniTaskCompletionSource Create()
|
||||
{
|
||||
var value = pool.TryRent() ?? new AutoResetUniTaskCompletionSource();
|
||||
TaskTracker.TrackActiveTask(value, 2);
|
||||
return value;
|
||||
if (!pool.TryPop(out var result))
|
||||
{
|
||||
result = new AutoResetUniTaskCompletionSource();
|
||||
}
|
||||
TaskTracker.TrackActiveTask(result, 2);
|
||||
return result;
|
||||
}
|
||||
|
||||
[DebuggerHidden]
|
||||
@@ -452,12 +461,11 @@ namespace Cysharp.Threading.Tasks
|
||||
{
|
||||
try
|
||||
{
|
||||
TaskTracker.RemoveTracking(this);
|
||||
core.GetResult(token);
|
||||
}
|
||||
finally
|
||||
{
|
||||
pool.TryReturn(this);
|
||||
TryReturn();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -481,14 +489,16 @@ namespace Cysharp.Threading.Tasks
|
||||
}
|
||||
|
||||
[DebuggerHidden]
|
||||
void IPromisePoolItem.Reset()
|
||||
bool TryReturn()
|
||||
{
|
||||
TaskTracker.RemoveTracking(this);
|
||||
core.Reset();
|
||||
return pool.TryPush(this);
|
||||
}
|
||||
|
||||
~AutoResetUniTaskCompletionSource()
|
||||
{
|
||||
if (pool.TryReturn(this))
|
||||
if (TryReturn())
|
||||
{
|
||||
GC.ReRegisterForFinalize(this);
|
||||
return;
|
||||
@@ -591,9 +601,15 @@ namespace Cysharp.Threading.Tasks
|
||||
}
|
||||
}
|
||||
|
||||
public class AutoResetUniTaskCompletionSource<T> : IUniTaskSource<T>, IPromisePoolItem, IPromise<T>
|
||||
public class AutoResetUniTaskCompletionSource<T> : IUniTaskSource<T>, ITaskPoolNode<AutoResetUniTaskCompletionSource<T>>, IPromise<T>
|
||||
{
|
||||
static readonly PromisePool<AutoResetUniTaskCompletionSource<T>> pool = new PromisePool<AutoResetUniTaskCompletionSource<T>>();
|
||||
static TaskPool<AutoResetUniTaskCompletionSource<T>> pool;
|
||||
public AutoResetUniTaskCompletionSource<T> NextNode { get; set; }
|
||||
|
||||
static AutoResetUniTaskCompletionSource()
|
||||
{
|
||||
TaskPoolMonitor.RegisterSizeGetter(typeof(AutoResetUniTaskCompletionSource<T>), () => pool.Size);
|
||||
}
|
||||
|
||||
UniTaskCompletionSourceCore<T> core;
|
||||
|
||||
@@ -604,7 +620,10 @@ namespace Cysharp.Threading.Tasks
|
||||
[DebuggerHidden]
|
||||
public static AutoResetUniTaskCompletionSource<T> Create()
|
||||
{
|
||||
var result = pool.TryRent() ?? new AutoResetUniTaskCompletionSource<T>();
|
||||
if (!pool.TryPop(out var result))
|
||||
{
|
||||
result = new AutoResetUniTaskCompletionSource<T>();
|
||||
}
|
||||
TaskTracker.TrackActiveTask(result, 2);
|
||||
return result;
|
||||
}
|
||||
@@ -668,12 +687,11 @@ namespace Cysharp.Threading.Tasks
|
||||
{
|
||||
try
|
||||
{
|
||||
TaskTracker.RemoveTracking(this);
|
||||
return core.GetResult(token);
|
||||
}
|
||||
finally
|
||||
{
|
||||
pool.TryReturn(this);
|
||||
TryReturn();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -702,14 +720,17 @@ namespace Cysharp.Threading.Tasks
|
||||
}
|
||||
|
||||
[DebuggerHidden]
|
||||
void IPromisePoolItem.Reset()
|
||||
bool TryReturn()
|
||||
{
|
||||
TaskTracker.RemoveTracking(this);
|
||||
core.Reset();
|
||||
return pool.TryPush(this);
|
||||
}
|
||||
|
||||
|
||||
~AutoResetUniTaskCompletionSource()
|
||||
{
|
||||
if (pool.TryReturn(this))
|
||||
if (TryReturn())
|
||||
{
|
||||
GC.ReRegisterForFinalize(this);
|
||||
}
|
||||
|
||||
@@ -571,7 +571,7 @@ namespace Cysharp.Threading.Tasks
|
||||
|
||||
#if UNITY_2018_3_OR_NEWER
|
||||
|
||||
class ToCoroutineEnumerator : IEnumerator
|
||||
sealed class ToCoroutineEnumerator : IEnumerator
|
||||
{
|
||||
bool completed;
|
||||
UniTask task;
|
||||
@@ -629,12 +629,12 @@ namespace Cysharp.Threading.Tasks
|
||||
return !completed;
|
||||
}
|
||||
|
||||
public void Reset()
|
||||
void IEnumerator.Reset()
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
class ToCoroutineEnumerator<T> : IEnumerator
|
||||
sealed class ToCoroutineEnumerator<T> : IEnumerator
|
||||
{
|
||||
bool completed;
|
||||
Action<T> resultHandler = null;
|
||||
@@ -700,11 +700,11 @@ namespace Cysharp.Threading.Tasks
|
||||
return !completed;
|
||||
}
|
||||
|
||||
public void Reset()
|
||||
void IEnumerator.Reset()
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,36 +14,6 @@ namespace Cysharp.Threading.Tasks
|
||||
public void Forget()
|
||||
{
|
||||
}
|
||||
|
||||
// [DebuggerHidden]
|
||||
// public Awaiter GetAwaiter()
|
||||
// {
|
||||
// return new Awaiter();
|
||||
// }
|
||||
|
||||
// public struct Awaiter : ICriticalNotifyCompletion
|
||||
// {
|
||||
// [DebuggerHidden]
|
||||
// public bool IsCompleted => true;
|
||||
|
||||
// [DebuggerHidden]
|
||||
// public void GetResult()
|
||||
// {
|
||||
//#if UNITY_2018_3_OR_NEWER
|
||||
// UnityEngine.Debug.LogWarning("UniTaskVoid can't await, always fire-and-forget. use Forget instead of await.");
|
||||
//#endif
|
||||
// }
|
||||
|
||||
// [DebuggerHidden]
|
||||
// public void OnCompleted(Action continuation)
|
||||
// {
|
||||
// }
|
||||
|
||||
// [DebuggerHidden]
|
||||
// public void UnsafeOnCompleted(Action continuation)
|
||||
// {
|
||||
// }
|
||||
// }
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -70,14 +70,20 @@ namespace Cysharp.Threading.Tasks
|
||||
public void UnsafeOnCompleted(Action continuation)
|
||||
{
|
||||
Error.ThrowWhenContinuationIsAlreadyRegistered(continuationAction);
|
||||
continuationAction = continuation.AsFuncOfT<AsyncOperation>(); // allocate delegate.
|
||||
continuationAction = PooledDelegate<AsyncOperation>.Create(continuation);
|
||||
asyncOperation.completed += continuationAction;
|
||||
}
|
||||
}
|
||||
|
||||
class AsyncOperationConfiguredSource : IUniTaskSource, IPlayerLoopItem, IPromisePoolItem
|
||||
class AsyncOperationConfiguredSource : IUniTaskSource, IPlayerLoopItem, ITaskPoolNode<AsyncOperationConfiguredSource>
|
||||
{
|
||||
static readonly PromisePool<AsyncOperationConfiguredSource> pool = new PromisePool<AsyncOperationConfiguredSource>();
|
||||
static TaskPool<AsyncOperationConfiguredSource> pool;
|
||||
public AsyncOperationConfiguredSource NextNode { get; set; }
|
||||
|
||||
static AsyncOperationConfiguredSource()
|
||||
{
|
||||
TaskPoolMonitor.RegisterSizeGetter(typeof(AsyncOperationConfiguredSource), () => pool.Size);
|
||||
}
|
||||
|
||||
AsyncOperation asyncOperation;
|
||||
IProgress<float> progress;
|
||||
@@ -97,7 +103,10 @@ namespace Cysharp.Threading.Tasks
|
||||
return AutoResetUniTaskCompletionSource.CreateFromCanceled(cancellationToken, out token);
|
||||
}
|
||||
|
||||
var result = pool.TryRent() ?? new AsyncOperationConfiguredSource();
|
||||
if (!pool.TryPop(out var result))
|
||||
{
|
||||
result = new AsyncOperationConfiguredSource();
|
||||
}
|
||||
|
||||
result.asyncOperation = asyncOperation;
|
||||
result.progress = progress;
|
||||
@@ -115,13 +124,12 @@ namespace Cysharp.Threading.Tasks
|
||||
{
|
||||
try
|
||||
{
|
||||
TaskTracker.RemoveTracking(this);
|
||||
|
||||
core.GetResult(token);
|
||||
}
|
||||
finally
|
||||
{
|
||||
pool.TryReturn(this);
|
||||
TryReturn();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -162,17 +170,19 @@ namespace Cysharp.Threading.Tasks
|
||||
return true;
|
||||
}
|
||||
|
||||
public void Reset()
|
||||
bool TryReturn()
|
||||
{
|
||||
TaskTracker.RemoveTracking(this);
|
||||
core.Reset();
|
||||
asyncOperation = default;
|
||||
progress = default;
|
||||
cancellationToken = default;
|
||||
return pool.TryPush(this);
|
||||
}
|
||||
|
||||
~AsyncOperationConfiguredSource()
|
||||
{
|
||||
if (pool.TryReturn(this))
|
||||
if (TryReturn())
|
||||
{
|
||||
GC.ReRegisterForFinalize(this);
|
||||
}
|
||||
@@ -242,14 +252,20 @@ namespace Cysharp.Threading.Tasks
|
||||
public void UnsafeOnCompleted(Action continuation)
|
||||
{
|
||||
Error.ThrowWhenContinuationIsAlreadyRegistered(continuationAction);
|
||||
continuationAction = continuation.AsFuncOfT<AsyncOperation>(); // allocate delegate.
|
||||
continuationAction = PooledDelegate<AsyncOperation>.Create(continuation);
|
||||
asyncOperation.completed += continuationAction;
|
||||
}
|
||||
}
|
||||
|
||||
class ResourceRequestConfiguredSource : IUniTaskSource<UnityEngine.Object>, IPlayerLoopItem, IPromisePoolItem
|
||||
class ResourceRequestConfiguredSource : IUniTaskSource<UnityEngine.Object>, IPlayerLoopItem, ITaskPoolNode<ResourceRequestConfiguredSource>
|
||||
{
|
||||
static readonly PromisePool<ResourceRequestConfiguredSource> pool = new PromisePool<ResourceRequestConfiguredSource>();
|
||||
static TaskPool<ResourceRequestConfiguredSource> pool;
|
||||
public ResourceRequestConfiguredSource NextNode { get; set; }
|
||||
|
||||
static ResourceRequestConfiguredSource()
|
||||
{
|
||||
TaskPoolMonitor.RegisterSizeGetter(typeof(ResourceRequestConfiguredSource), () => pool.Size);
|
||||
}
|
||||
|
||||
ResourceRequest asyncOperation;
|
||||
IProgress<float> progress;
|
||||
@@ -269,7 +285,10 @@ namespace Cysharp.Threading.Tasks
|
||||
return AutoResetUniTaskCompletionSource<UnityEngine.Object>.CreateFromCanceled(cancellationToken, out token);
|
||||
}
|
||||
|
||||
var result = pool.TryRent() ?? new ResourceRequestConfiguredSource();
|
||||
if (!pool.TryPop(out var result))
|
||||
{
|
||||
result = new ResourceRequestConfiguredSource();
|
||||
}
|
||||
|
||||
result.asyncOperation = asyncOperation;
|
||||
result.progress = progress;
|
||||
@@ -287,13 +306,12 @@ namespace Cysharp.Threading.Tasks
|
||||
{
|
||||
try
|
||||
{
|
||||
TaskTracker.RemoveTracking(this);
|
||||
|
||||
return core.GetResult(token);
|
||||
}
|
||||
finally
|
||||
{
|
||||
pool.TryReturn(this);
|
||||
TryReturn();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -339,17 +357,19 @@ namespace Cysharp.Threading.Tasks
|
||||
return true;
|
||||
}
|
||||
|
||||
public void Reset()
|
||||
bool TryReturn()
|
||||
{
|
||||
TaskTracker.RemoveTracking(this);
|
||||
core.Reset();
|
||||
asyncOperation = default;
|
||||
progress = default;
|
||||
cancellationToken = default;
|
||||
return pool.TryPush(this);
|
||||
}
|
||||
|
||||
~ResourceRequestConfiguredSource()
|
||||
{
|
||||
if (pool.TryReturn(this))
|
||||
if (TryReturn())
|
||||
{
|
||||
GC.ReRegisterForFinalize(this);
|
||||
}
|
||||
@@ -419,14 +439,20 @@ namespace Cysharp.Threading.Tasks
|
||||
public void UnsafeOnCompleted(Action continuation)
|
||||
{
|
||||
Error.ThrowWhenContinuationIsAlreadyRegistered(continuationAction);
|
||||
continuationAction = continuation.AsFuncOfT<AsyncOperation>(); // allocate delegate.
|
||||
continuationAction = PooledDelegate<AsyncOperation>.Create(continuation);
|
||||
asyncOperation.completed += continuationAction;
|
||||
}
|
||||
}
|
||||
|
||||
class AssetBundleRequestConfiguredSource : IUniTaskSource<UnityEngine.Object>, IPlayerLoopItem, IPromisePoolItem
|
||||
class AssetBundleRequestConfiguredSource : IUniTaskSource<UnityEngine.Object>, IPlayerLoopItem, ITaskPoolNode<AssetBundleRequestConfiguredSource>
|
||||
{
|
||||
static readonly PromisePool<AssetBundleRequestConfiguredSource> pool = new PromisePool<AssetBundleRequestConfiguredSource>();
|
||||
static TaskPool<AssetBundleRequestConfiguredSource> pool;
|
||||
public AssetBundleRequestConfiguredSource NextNode { get; set; }
|
||||
|
||||
static AssetBundleRequestConfiguredSource()
|
||||
{
|
||||
TaskPoolMonitor.RegisterSizeGetter(typeof(AssetBundleRequestConfiguredSource), () => pool.Size);
|
||||
}
|
||||
|
||||
AssetBundleRequest asyncOperation;
|
||||
IProgress<float> progress;
|
||||
@@ -446,7 +472,10 @@ namespace Cysharp.Threading.Tasks
|
||||
return AutoResetUniTaskCompletionSource<UnityEngine.Object>.CreateFromCanceled(cancellationToken, out token);
|
||||
}
|
||||
|
||||
var result = pool.TryRent() ?? new AssetBundleRequestConfiguredSource();
|
||||
if (!pool.TryPop(out var result))
|
||||
{
|
||||
result = new AssetBundleRequestConfiguredSource();
|
||||
}
|
||||
|
||||
result.asyncOperation = asyncOperation;
|
||||
result.progress = progress;
|
||||
@@ -464,13 +493,11 @@ namespace Cysharp.Threading.Tasks
|
||||
{
|
||||
try
|
||||
{
|
||||
TaskTracker.RemoveTracking(this);
|
||||
|
||||
return core.GetResult(token);
|
||||
}
|
||||
finally
|
||||
{
|
||||
pool.TryReturn(this);
|
||||
TryReturn();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -516,17 +543,19 @@ namespace Cysharp.Threading.Tasks
|
||||
return true;
|
||||
}
|
||||
|
||||
public void Reset()
|
||||
bool TryReturn()
|
||||
{
|
||||
core.Reset();
|
||||
asyncOperation = default;
|
||||
progress = default;
|
||||
cancellationToken = default;
|
||||
TaskTracker.RemoveTracking(this);
|
||||
return pool.TryPush(this);
|
||||
}
|
||||
|
||||
~AssetBundleRequestConfiguredSource()
|
||||
{
|
||||
if (pool.TryReturn(this))
|
||||
if (TryReturn())
|
||||
{
|
||||
GC.ReRegisterForFinalize(this);
|
||||
}
|
||||
@@ -596,14 +625,20 @@ namespace Cysharp.Threading.Tasks
|
||||
public void UnsafeOnCompleted(Action continuation)
|
||||
{
|
||||
Error.ThrowWhenContinuationIsAlreadyRegistered(continuationAction);
|
||||
continuationAction = continuation.AsFuncOfT<AsyncOperation>(); // allocate delegate.
|
||||
continuationAction = PooledDelegate<AsyncOperation>.Create(continuation);
|
||||
asyncOperation.completed += continuationAction;
|
||||
}
|
||||
}
|
||||
|
||||
class AssetBundleCreateRequestConfiguredSource : IUniTaskSource<AssetBundle>, IPlayerLoopItem, IPromisePoolItem
|
||||
class AssetBundleCreateRequestConfiguredSource : IUniTaskSource<AssetBundle>, IPlayerLoopItem, ITaskPoolNode<AssetBundleCreateRequestConfiguredSource>
|
||||
{
|
||||
static readonly PromisePool<AssetBundleCreateRequestConfiguredSource> pool = new PromisePool<AssetBundleCreateRequestConfiguredSource>();
|
||||
static TaskPool<AssetBundleCreateRequestConfiguredSource> pool;
|
||||
public AssetBundleCreateRequestConfiguredSource NextNode { get; set; }
|
||||
|
||||
static AssetBundleCreateRequestConfiguredSource()
|
||||
{
|
||||
TaskPoolMonitor.RegisterSizeGetter(typeof(AssetBundleCreateRequestConfiguredSource), () => pool.Size);
|
||||
}
|
||||
|
||||
AssetBundleCreateRequest asyncOperation;
|
||||
IProgress<float> progress;
|
||||
@@ -623,7 +658,10 @@ namespace Cysharp.Threading.Tasks
|
||||
return AutoResetUniTaskCompletionSource<AssetBundle>.CreateFromCanceled(cancellationToken, out token);
|
||||
}
|
||||
|
||||
var result = pool.TryRent() ?? new AssetBundleCreateRequestConfiguredSource();
|
||||
if (!pool.TryPop(out var result))
|
||||
{
|
||||
result = new AssetBundleCreateRequestConfiguredSource();
|
||||
}
|
||||
|
||||
result.asyncOperation = asyncOperation;
|
||||
result.progress = progress;
|
||||
@@ -641,13 +679,11 @@ namespace Cysharp.Threading.Tasks
|
||||
{
|
||||
try
|
||||
{
|
||||
TaskTracker.RemoveTracking(this);
|
||||
|
||||
return core.GetResult(token);
|
||||
}
|
||||
finally
|
||||
{
|
||||
pool.TryReturn(this);
|
||||
TryReturn();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -693,17 +729,19 @@ namespace Cysharp.Threading.Tasks
|
||||
return true;
|
||||
}
|
||||
|
||||
public void Reset()
|
||||
bool TryReturn()
|
||||
{
|
||||
core.Reset();
|
||||
asyncOperation = default;
|
||||
progress = default;
|
||||
cancellationToken = default;
|
||||
TaskTracker.RemoveTracking(this);
|
||||
return pool.TryPush(this);
|
||||
}
|
||||
|
||||
~AssetBundleCreateRequestConfiguredSource()
|
||||
{
|
||||
if (pool.TryReturn(this))
|
||||
if (TryReturn())
|
||||
{
|
||||
GC.ReRegisterForFinalize(this);
|
||||
}
|
||||
@@ -774,14 +812,20 @@ namespace Cysharp.Threading.Tasks
|
||||
public void UnsafeOnCompleted(Action continuation)
|
||||
{
|
||||
Error.ThrowWhenContinuationIsAlreadyRegistered(continuationAction);
|
||||
continuationAction = continuation.AsFuncOfT<AsyncOperation>(); // allocate delegate.
|
||||
continuationAction = PooledDelegate<AsyncOperation>.Create(continuation);
|
||||
asyncOperation.completed += continuationAction;
|
||||
}
|
||||
}
|
||||
|
||||
class UnityWebRequestAsyncOperationConfiguredSource : IUniTaskSource<UnityWebRequest>, IPlayerLoopItem, IPromisePoolItem
|
||||
class UnityWebRequestAsyncOperationConfiguredSource : IUniTaskSource<UnityWebRequest>, IPlayerLoopItem, ITaskPoolNode<UnityWebRequestAsyncOperationConfiguredSource>
|
||||
{
|
||||
static readonly PromisePool<UnityWebRequestAsyncOperationConfiguredSource> pool = new PromisePool<UnityWebRequestAsyncOperationConfiguredSource>();
|
||||
static TaskPool<UnityWebRequestAsyncOperationConfiguredSource> pool;
|
||||
public UnityWebRequestAsyncOperationConfiguredSource NextNode { get; set; }
|
||||
|
||||
static UnityWebRequestAsyncOperationConfiguredSource()
|
||||
{
|
||||
TaskPoolMonitor.RegisterSizeGetter(typeof(UnityWebRequestAsyncOperationConfiguredSource), () => pool.Size);
|
||||
}
|
||||
|
||||
UnityWebRequestAsyncOperation asyncOperation;
|
||||
IProgress<float> progress;
|
||||
@@ -801,7 +845,10 @@ namespace Cysharp.Threading.Tasks
|
||||
return AutoResetUniTaskCompletionSource<UnityWebRequest>.CreateFromCanceled(cancellationToken, out token);
|
||||
}
|
||||
|
||||
var result = pool.TryRent() ?? new UnityWebRequestAsyncOperationConfiguredSource();
|
||||
if (!pool.TryPop(out var result))
|
||||
{
|
||||
result = new UnityWebRequestAsyncOperationConfiguredSource();
|
||||
}
|
||||
|
||||
result.asyncOperation = asyncOperation;
|
||||
result.progress = progress;
|
||||
@@ -819,13 +866,12 @@ namespace Cysharp.Threading.Tasks
|
||||
{
|
||||
try
|
||||
{
|
||||
TaskTracker.RemoveTracking(this);
|
||||
|
||||
return core.GetResult(token);
|
||||
}
|
||||
finally
|
||||
{
|
||||
pool.TryReturn(this);
|
||||
TryReturn();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -872,17 +918,19 @@ namespace Cysharp.Threading.Tasks
|
||||
return true;
|
||||
}
|
||||
|
||||
public void Reset()
|
||||
bool TryReturn()
|
||||
{
|
||||
core.Reset();
|
||||
asyncOperation = default;
|
||||
progress = default;
|
||||
cancellationToken = default;
|
||||
TaskTracker.RemoveTracking(this);
|
||||
return pool.TryPush(this);
|
||||
}
|
||||
|
||||
~UnityWebRequestAsyncOperationConfiguredSource()
|
||||
{
|
||||
if (pool.TryReturn(this))
|
||||
if (TryReturn())
|
||||
{
|
||||
GC.ReRegisterForFinalize(this);
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "com.cysharp.unitask",
|
||||
"displayName": "UniTask",
|
||||
"version": "2.0.11-rc8",
|
||||
"version": "2.0.12-rc9",
|
||||
"unity": "2019.1",
|
||||
"description": "Provides an efficient async/await integration to Unity.",
|
||||
"keywords": [ "async/await", "async", "Task", "UniTask" ],
|
||||
|
||||
@@ -13,7 +13,6 @@ using UnityEngine;
|
||||
using UnityEngine.Networking;
|
||||
using UnityEngine.UI;
|
||||
|
||||
|
||||
// using DG.Tweening;
|
||||
|
||||
public struct MyJob : IJob
|
||||
@@ -259,11 +258,15 @@ public class SandboxMain : MonoBehaviour
|
||||
{
|
||||
try
|
||||
{
|
||||
var cts = new CancellationTokenSource();
|
||||
var r = UniAsync("https://bing.com/", cts.Token);
|
||||
cts.Cancel();
|
||||
await r;
|
||||
Debug.Log("UNIASYNC");
|
||||
//var cts = new CancellationTokenSource();
|
||||
//var r = UniAsync("https://bing.com/", cts.Token);
|
||||
//cts.Cancel();
|
||||
//await r;
|
||||
_ = await UnityWebRequest.Get("https://bing.com/").SendWebRequest();
|
||||
Debug.Log("UNIASYNC1 ");
|
||||
|
||||
_ = await UnityWebRequest.Get("https://bing.com/").SendWebRequest();
|
||||
Debug.Log("UNIASYNC2");
|
||||
}
|
||||
catch
|
||||
{
|
||||
@@ -291,7 +294,7 @@ public class SandboxMain : MonoBehaviour
|
||||
}
|
||||
|
||||
|
||||
void Start()
|
||||
async UniTaskVoid Start()
|
||||
{
|
||||
//UniTaskAsyncEnumerable.EveryValueChanged(mcc, x => x.MyProperty)
|
||||
// .Do(_ => { }, () => Debug.Log("COMPLETED"))
|
||||
@@ -301,15 +304,23 @@ public class SandboxMain : MonoBehaviour
|
||||
// })
|
||||
// .Forget();
|
||||
|
||||
_ = Test1();
|
||||
//_ = Test1();
|
||||
Test2().Forget();
|
||||
StartCoroutine(Test3("https://bing.com/"));
|
||||
//StartCoroutine(Test3("https://bing.com/"));
|
||||
|
||||
|
||||
// DG.Tweening.Core.TweenerCore<int>
|
||||
//okButton.GetComponent<RectTransform>().DOMoveX(10.2f, 30);
|
||||
//Debug.Log("GO MOVEX");
|
||||
//await okButton.GetComponent<RectTransform>().DOMoveX(-10.2f, 3).WithCancellation(CancellationToken.None);
|
||||
//Debug.Log("END MOVEX");
|
||||
|
||||
|
||||
//Debug.Log("AGAIN MOVE");
|
||||
//await okButton.GetComponent<RectTransform>().DOMoveY(10.2f, 3).WithCancellation(CancellationToken.None);
|
||||
//Debug.Log("AGAIN END MOVE");
|
||||
|
||||
|
||||
await UniTask.Yield();
|
||||
// DOTween.To(
|
||||
|
||||
var cts = new CancellationTokenSource();
|
||||
@@ -343,14 +354,17 @@ public class SandboxMain : MonoBehaviour
|
||||
|
||||
}).Forget();
|
||||
|
||||
|
||||
CloseAsync(this.GetCancellationTokenOnDestroy()).Forget();
|
||||
|
||||
okButton.onClick.AddListener(UniTask.UnityAction(async () => await UniTask.Yield()));
|
||||
}
|
||||
|
||||
async UniTaskVoid CloseAsync(CancellationToken cancellationToken = default)
|
||||
{
|
||||
await UniTask.Yield();
|
||||
while (true)
|
||||
{
|
||||
await UniTask.Yield(PlayerLoopTiming.Update, cancellationToken);
|
||||
}
|
||||
}
|
||||
|
||||
async UniTaskVoid Running(CancellationToken ct)
|
||||
|
||||
165
src/UniTask/Assets/Tests/GenericsWhenAllAny.cs
Normal file
165
src/UniTask/Assets/Tests/GenericsWhenAllAny.cs
Normal file
@@ -0,0 +1,165 @@
|
||||
#if CSHARP_7_OR_LATER || (UNITY_2018_3_OR_NEWER && (NET_STANDARD_2_0 || NET_4_6))
|
||||
#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member
|
||||
|
||||
using UnityEngine;
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using UnityEngine.UI;
|
||||
using UnityEngine.Scripting;
|
||||
using Cysharp.Threading.Tasks;
|
||||
using Unity.Collections;
|
||||
using System.Threading;
|
||||
using NUnit.Framework;
|
||||
using UnityEngine.TestTools;
|
||||
using FluentAssertions;
|
||||
|
||||
namespace Cysharp.Threading.TasksTests
|
||||
{
|
||||
public class GenericsWhenAllAny
|
||||
{
|
||||
|
||||
[UnityTest]
|
||||
public IEnumerator WhenAllT15() => UniTask.ToCoroutine(async () =>
|
||||
{
|
||||
var t01 = Tes<int>();
|
||||
var t02 = Tes<int>();
|
||||
var t03 = Tes<int>();
|
||||
var t04 = Tes<int>();
|
||||
var t05 = Tes<int>();
|
||||
var t06 = Tes<int>();
|
||||
var t07 = Tes<int>();
|
||||
var t08 = Tes<int>();
|
||||
var t09 = Tes<int>();
|
||||
var t10 = Tes<int>();
|
||||
var t11 = Tes<int>();
|
||||
var t12 = Tes<int>();
|
||||
var t13 = Tes<int>();
|
||||
var t14 = Tes<int>();
|
||||
var t15 = Tes<int>();
|
||||
|
||||
await UniTask.WhenAll(t01, t02, t03, t04, t05, t06, t07, t08, t09, t10, t11, t12, t13, t14, t15);
|
||||
});
|
||||
|
||||
[UnityTest]
|
||||
public IEnumerator WhenAllT01_Generics1() => UniTask.ToCoroutine(async () =>
|
||||
{
|
||||
var t01 = Tes<MyGenerics<int>>();
|
||||
|
||||
await UniTask.WhenAll(t01);
|
||||
});
|
||||
|
||||
[UnityTest]
|
||||
public IEnumerator WhenAllT02_Generics1() => UniTask.ToCoroutine(async () =>
|
||||
{
|
||||
var t01 = Tes<MyGenerics<int>>();
|
||||
var t02 = Tes<MyGenerics<int>>();
|
||||
|
||||
await UniTask.WhenAll(t01, t02);
|
||||
});
|
||||
|
||||
[UnityTest]
|
||||
public IEnumerator WhenAllT03_Generics1() => UniTask.ToCoroutine(async () =>
|
||||
{
|
||||
var t01 = Tes<MyGenerics<int>>();
|
||||
var t02 = Tes<MyGenerics<int>>();
|
||||
var t03 = Tes<MyGenerics<int>>();
|
||||
|
||||
await UniTask.WhenAll(t01, t02, t03);
|
||||
});
|
||||
|
||||
[UnityTest]
|
||||
public IEnumerator WhenAllT04_Generics1() => UniTask.ToCoroutine(async () =>
|
||||
{
|
||||
var t01 = Tes<MyGenerics<int>>();
|
||||
var t02 = Tes<MyGenerics<int>>();
|
||||
var t03 = Tes<MyGenerics<int>>();
|
||||
var t04 = Tes<MyGenerics<int>>();
|
||||
|
||||
await UniTask.WhenAll(t01, t02, t03, t04);
|
||||
});
|
||||
|
||||
// will fail.
|
||||
|
||||
//[UnityTest]
|
||||
//public IEnumerator WhenAllT05_Generics1() => UniTask.ToCoroutine(async () =>
|
||||
//{
|
||||
// var t01 = Tes<MyGenerics<int>>();
|
||||
// var t02 = Tes<MyGenerics<int>>();
|
||||
// var t03 = Tes<MyGenerics<int>>();
|
||||
// var t04 = Tes<MyGenerics<int>>();
|
||||
// var t05 = Tes<MyGenerics<int>>();
|
||||
|
||||
// await UniTask.WhenAll(t01, t02, t03, t04, t05);
|
||||
//});
|
||||
|
||||
//[UnityTest]
|
||||
//public IEnumerator WhenAllT06_Generics1() => UniTask.ToCoroutine(async () =>
|
||||
//{
|
||||
// var t01 = Tes<MyGenerics<int>>();
|
||||
// var t02 = Tes<MyGenerics<int>>();
|
||||
// var t03 = Tes<MyGenerics<int>>();
|
||||
// var t04 = Tes<MyGenerics<int>>();
|
||||
// var t05 = Tes<MyGenerics<int>>();
|
||||
// var t06 = Tes<MyGenerics<int>>();
|
||||
|
||||
// await UniTask.WhenAll(t01, t02, t03, t04, t05, t06);
|
||||
//});
|
||||
|
||||
//[UnityTest]
|
||||
//public IEnumerator WhenAllT07_Generics1() => UniTask.ToCoroutine(async () =>
|
||||
//{
|
||||
// var t01 = Tes<MyGenerics<int>>();
|
||||
// var t02 = Tes<MyGenerics<int>>();
|
||||
// var t03 = Tes<MyGenerics<int>>();
|
||||
// var t04 = Tes<MyGenerics<int>>();
|
||||
// var t05 = Tes<MyGenerics<int>>();
|
||||
// var t06 = Tes<MyGenerics<int>>();
|
||||
// var t07 = Tes<MyGenerics<int>>();
|
||||
|
||||
// await UniTask.WhenAll(t01, t02, t03, t04, t05, t06, t07);
|
||||
//});
|
||||
|
||||
//[UnityTest]
|
||||
//public IEnumerator WhenAllT15_Generics1() => UniTask.ToCoroutine(async () =>
|
||||
//{
|
||||
// var t01 = Tes<MyGenerics<int>>();
|
||||
// var t02 = Tes<MyGenerics<int>>();
|
||||
// var t03 = Tes<MyGenerics<int>>();
|
||||
// var t04 = Tes<MyGenerics<int>>();
|
||||
// var t05 = Tes<MyGenerics<int>>();
|
||||
// var t06 = Tes<MyGenerics<int>>();
|
||||
// var t07 = Tes<MyGenerics<int>>();
|
||||
// var t08 = Tes<MyGenerics<int>>();
|
||||
// var t09 = Tes<MyGenerics<int>>();
|
||||
// var t10 = Tes<MyGenerics<int>>();
|
||||
// var t11 = Tes<MyGenerics<int>>();
|
||||
// var t12 = Tes<MyGenerics<int>>();
|
||||
// var t13 = Tes<MyGenerics<int>>();
|
||||
// var t14 = Tes<MyGenerics<int>>();
|
||||
// var t15 = Tes<MyGenerics<int>>();
|
||||
|
||||
// await UniTask.WhenAll(t01, t02, t03, t04, t05, t06, t07, t08, t09, t10, t11, t12, t13, t14, t15);
|
||||
//});
|
||||
|
||||
async UniTask<T> Tes<T>()
|
||||
{
|
||||
await UniTask.Yield();
|
||||
return default;
|
||||
}
|
||||
}
|
||||
|
||||
public class MyGenerics<T>
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public class MyGenerics2
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
11
src/UniTask/Assets/Tests/GenericsWhenAllAny.cs.meta
Normal file
11
src/UniTask/Assets/Tests/GenericsWhenAllAny.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 6ce87069a3c0ebb47b26dca280a07756
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
Reference in New Issue
Block a user