mirror of
https://github.com/Cysharp/UniTask.git
synced 2026-05-15 03:20:16 +00:00
Compare commits
18 Commits
2.0.10-rc7
...
2.0.11-rc8
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
35b933730b | ||
|
|
7ab9467069 | ||
|
|
598312ba61 | ||
|
|
985aa5c43a | ||
|
|
10eff95a42 | ||
|
|
d27d6d5d9d | ||
|
|
b8c109848e | ||
|
|
8b7f832c0f | ||
|
|
7cce0f48e5 | ||
|
|
8a56838111 | ||
|
|
ff15e00003 | ||
|
|
f60d2c51fb | ||
|
|
6dfb969015 | ||
|
|
da7e9fc4b3 | ||
|
|
70385c4115 | ||
|
|
51ba740413 | ||
|
|
f3e3ba8864 | ||
|
|
07cf65c1ec |
@@ -1,123 +1,30 @@
|
||||
#pragma warning disable 0649
|
||||
|
||||
using System;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Threading.Tasks;
|
||||
using System.Threading.Tasks.Sources;
|
||||
|
||||
namespace Cysharp.Threading.Tasks
|
||||
{
|
||||
public static class UniTaskValueTaskExtensions
|
||||
{
|
||||
public static ValueTask AsValueTask(this UniTask task)
|
||||
public static ValueTask AsValueTask(this in UniTask task)
|
||||
{
|
||||
ref var core = ref Unsafe.As<UniTask, UniTaskToValueTask>(ref task);
|
||||
if (core.source == null)
|
||||
{
|
||||
return default;
|
||||
}
|
||||
|
||||
return new ValueTask(new UniTaskValueTaskSource(core.source), core.token);
|
||||
return task;
|
||||
}
|
||||
|
||||
public static ValueTask<T> AsValueTask<T>(this UniTask<T> task)
|
||||
public static ValueTask<T> AsValueTask<T>(this in UniTask<T> task)
|
||||
{
|
||||
ref var core = ref Unsafe.As<UniTask<T>, UniTaskToValueTask<T>>(ref task);
|
||||
if (core.source == null)
|
||||
{
|
||||
return new ValueTask<T>(core.result);
|
||||
}
|
||||
|
||||
return new ValueTask<T>(new UniTaskValueTaskSource<T>(core.source), core.token);
|
||||
return task;
|
||||
}
|
||||
|
||||
struct UniTaskToValueTask
|
||||
public static UniTask<T> AsUniTask<T>(this ValueTask<T> task, bool useCurrentSynchronizationContext = true)
|
||||
{
|
||||
public IUniTaskSource source;
|
||||
public short token;
|
||||
// NOTE: get _obj and _token directly for low overhead conversion but not yet implemented.
|
||||
return task.AsTask().AsUniTask(useCurrentSynchronizationContext);
|
||||
}
|
||||
|
||||
class UniTaskValueTaskSource : IValueTaskSource
|
||||
public static UniTask AsUniTask(this ValueTask task, bool useCurrentSynchronizationContext = true)
|
||||
{
|
||||
readonly IUniTaskSource source;
|
||||
|
||||
public UniTaskValueTaskSource(IUniTaskSource source)
|
||||
{
|
||||
this.source = source;
|
||||
}
|
||||
|
||||
public void GetResult(short token)
|
||||
{
|
||||
source.GetResult(token);
|
||||
}
|
||||
|
||||
public ValueTaskSourceStatus GetStatus(short token)
|
||||
{
|
||||
var status = source.GetStatus(token);
|
||||
switch (status)
|
||||
{
|
||||
case UniTaskStatus.Pending:
|
||||
return ValueTaskSourceStatus.Pending;
|
||||
case UniTaskStatus.Succeeded:
|
||||
return ValueTaskSourceStatus.Succeeded;
|
||||
case UniTaskStatus.Faulted:
|
||||
return ValueTaskSourceStatus.Faulted;
|
||||
case UniTaskStatus.Canceled:
|
||||
return ValueTaskSourceStatus.Canceled;
|
||||
default:
|
||||
return (ValueTaskSourceStatus)status;
|
||||
}
|
||||
}
|
||||
|
||||
public void OnCompleted(Action<object> continuation, object state, short token, ValueTaskSourceOnCompletedFlags flags)
|
||||
{
|
||||
source.OnCompleted(continuation, state, token);
|
||||
}
|
||||
}
|
||||
|
||||
struct UniTaskToValueTask<T>
|
||||
{
|
||||
public IUniTaskSource<T> source;
|
||||
public T result;
|
||||
public short token;
|
||||
}
|
||||
|
||||
class UniTaskValueTaskSource<T> : IValueTaskSource<T>
|
||||
{
|
||||
readonly IUniTaskSource<T> source;
|
||||
|
||||
public UniTaskValueTaskSource(IUniTaskSource<T> source)
|
||||
{
|
||||
this.source = source;
|
||||
}
|
||||
|
||||
public T GetResult(short token)
|
||||
{
|
||||
return source.GetResult(token);
|
||||
}
|
||||
|
||||
public ValueTaskSourceStatus GetStatus(short token)
|
||||
{
|
||||
var status = source.GetStatus(token);
|
||||
switch (status)
|
||||
{
|
||||
case UniTaskStatus.Pending:
|
||||
return ValueTaskSourceStatus.Pending;
|
||||
case UniTaskStatus.Succeeded:
|
||||
return ValueTaskSourceStatus.Succeeded;
|
||||
case UniTaskStatus.Faulted:
|
||||
return ValueTaskSourceStatus.Faulted;
|
||||
case UniTaskStatus.Canceled:
|
||||
return ValueTaskSourceStatus.Canceled;
|
||||
default:
|
||||
return (ValueTaskSourceStatus)status;
|
||||
}
|
||||
}
|
||||
|
||||
public void OnCompleted(Action<object> continuation, object state, short token, ValueTaskSourceOnCompletedFlags flags)
|
||||
{
|
||||
source.OnCompleted(continuation, state, token);
|
||||
}
|
||||
return task.AsTask().AsUniTask(useCurrentSynchronizationContext);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
using System;
|
||||
using Cysharp.Threading.Tasks.Internal;
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Threading;
|
||||
|
||||
@@ -41,7 +43,11 @@ namespace Cysharp.Threading.Tasks
|
||||
}
|
||||
else
|
||||
{
|
||||
#if NETCOREAPP3_1
|
||||
ThreadPool.UnsafeQueueUserWorkItem(ThreadPoolWorkItem.Create(continuation), false);
|
||||
#else
|
||||
ThreadPool.UnsafeQueueUserWorkItem(WaitCallbackDelegate, continuation);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
@@ -50,6 +56,39 @@ namespace Cysharp.Threading.Tasks
|
||||
((Action)state).Invoke();
|
||||
}
|
||||
}
|
||||
|
||||
#if NETCOREAPP3_1
|
||||
|
||||
public sealed class ThreadPoolWorkItem : IThreadPoolWorkItem
|
||||
{
|
||||
static readonly ConcurrentQueue<ThreadPoolWorkItem> pool = new ConcurrentQueue<ThreadPoolWorkItem>();
|
||||
|
||||
Action continuation;
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static ThreadPoolWorkItem Create(Action continuation)
|
||||
{
|
||||
if (!pool.TryDequeue(out var item))
|
||||
{
|
||||
item = new ThreadPoolWorkItem();
|
||||
}
|
||||
|
||||
item.continuation = continuation;
|
||||
return item;
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public void Execute()
|
||||
{
|
||||
var call = continuation;
|
||||
continuation = null;
|
||||
pool.Enqueue(this);
|
||||
|
||||
call.Invoke();
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,8 +1,9 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>netstandard2.0</TargetFramework>
|
||||
<TargetFrameworks>netcoreapp3.1;netstandard2.1</TargetFrameworks>
|
||||
<AssemblyName>UniTask</AssemblyName>
|
||||
<LangVersion>8.0</LangVersion>
|
||||
<RootNamespace>Cysharp.Threading.Tasks</RootNamespace>
|
||||
</PropertyGroup>
|
||||
|
||||
|
||||
198
src/UniTask.NetCoreSandbox/AllocationCheck.cs
Normal file
198
src/UniTask.NetCoreSandbox/AllocationCheck.cs
Normal file
@@ -0,0 +1,198 @@
|
||||
using BenchmarkDotNet.Attributes;
|
||||
using System.Linq;
|
||||
using BenchmarkDotNet.Configs;
|
||||
using BenchmarkDotNet.Diagnosers;
|
||||
using BenchmarkDotNet.Exporters;
|
||||
using BenchmarkDotNet.Jobs;
|
||||
using BenchmarkDotNet.Running;
|
||||
using Cysharp.Threading.Tasks;
|
||||
using PooledAwait;
|
||||
using System;
|
||||
using System.Runtime.ExceptionServices;
|
||||
using System.Threading.Tasks;
|
||||
using System.Threading;
|
||||
using System.Runtime.CompilerServices;
|
||||
using Cysharp.Threading.Tasks.CompilerServices;
|
||||
using System.Collections.Concurrent;
|
||||
|
||||
[Config(typeof(BenchmarkConfig))]
|
||||
public class AllocationCheck
|
||||
{
|
||||
// note: all the benchmarks use Task/Task<T> for the public API, because BenchmarkDotNet
|
||||
// doesn't work reliably with more exotic task-types (even just ValueTask fails); instead,
|
||||
// we'll obscure the cost of the outer awaitable by doing a relatively large number of
|
||||
// iterations, so that we're only really measuring the inner loop
|
||||
private const int InnerOps = 1000;
|
||||
|
||||
[Benchmark(OperationsPerInvoke = InnerOps)]
|
||||
public async Task ViaUniTask()
|
||||
{
|
||||
for (int i = 0; i < InnerOps; i++)
|
||||
{
|
||||
await Core();
|
||||
}
|
||||
|
||||
static async UniTask Core()
|
||||
{
|
||||
await new TestAwaiter(false, UniTaskStatus.Succeeded);
|
||||
await new TestAwaiter(false, UniTaskStatus.Succeeded);
|
||||
await new TestAwaiter(false, UniTaskStatus.Succeeded);
|
||||
}
|
||||
}
|
||||
|
||||
[Benchmark(OperationsPerInvoke = InnerOps)]
|
||||
public async Task<int> ViaUniTaskT()
|
||||
{
|
||||
var sum = 0;
|
||||
for (int i = 0; i < InnerOps; i++)
|
||||
{
|
||||
sum += await Core();
|
||||
}
|
||||
return sum;
|
||||
|
||||
static async UniTask<int> Core()
|
||||
{
|
||||
var a = await new TestAwaiter<int>(false, UniTaskStatus.Succeeded, 10);
|
||||
var b = await new TestAwaiter<int>(false, UniTaskStatus.Succeeded, 10);
|
||||
var c = await new TestAwaiter<int>(false, UniTaskStatus.Succeeded, 10);
|
||||
return 10;
|
||||
}
|
||||
}
|
||||
|
||||
[Benchmark(OperationsPerInvoke = InnerOps)]
|
||||
public Task ViaUniTaskVoid()
|
||||
{
|
||||
for (int i = 0; i < InnerOps; i++)
|
||||
{
|
||||
Core().Forget();
|
||||
}
|
||||
return Task.CompletedTask;
|
||||
|
||||
static async UniTaskVoid Core()
|
||||
{
|
||||
await new TestAwaiter(false, UniTaskStatus.Succeeded);
|
||||
await new TestAwaiter(false, UniTaskStatus.Succeeded);
|
||||
await new TestAwaiter(false, UniTaskStatus.Succeeded);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public class TaskTestException : Exception
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public struct TestAwaiter : ICriticalNotifyCompletion
|
||||
{
|
||||
readonly UniTaskStatus status;
|
||||
readonly bool isCompleted;
|
||||
|
||||
public TestAwaiter(bool isCompleted, UniTaskStatus status)
|
||||
{
|
||||
this.isCompleted = isCompleted;
|
||||
this.status = status;
|
||||
}
|
||||
|
||||
public TestAwaiter GetAwaiter() => this;
|
||||
|
||||
public bool IsCompleted => isCompleted;
|
||||
|
||||
public void GetResult()
|
||||
{
|
||||
switch (status)
|
||||
{
|
||||
case UniTaskStatus.Faulted:
|
||||
throw new TaskTestException();
|
||||
case UniTaskStatus.Canceled:
|
||||
throw new OperationCanceledException();
|
||||
case UniTaskStatus.Pending:
|
||||
case UniTaskStatus.Succeeded:
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
public void OnCompleted(Action continuation)
|
||||
{
|
||||
ThreadPool.UnsafeQueueUserWorkItem(ThreadPoolWorkItem.Create(continuation), false);
|
||||
}
|
||||
|
||||
public void UnsafeOnCompleted(Action continuation)
|
||||
{
|
||||
ThreadPool.UnsafeQueueUserWorkItem(ThreadPoolWorkItem.Create(continuation), false);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
public struct TestAwaiter<T> : ICriticalNotifyCompletion
|
||||
{
|
||||
readonly UniTaskStatus status;
|
||||
readonly bool isCompleted;
|
||||
readonly T value;
|
||||
|
||||
public TestAwaiter(bool isCompleted, UniTaskStatus status, T value)
|
||||
{
|
||||
this.isCompleted = isCompleted;
|
||||
this.status = status;
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
public TestAwaiter<T> GetAwaiter() => this;
|
||||
|
||||
public bool IsCompleted => isCompleted;
|
||||
|
||||
public T GetResult()
|
||||
{
|
||||
switch (status)
|
||||
{
|
||||
case UniTaskStatus.Faulted:
|
||||
throw new TaskTestException();
|
||||
case UniTaskStatus.Canceled:
|
||||
throw new OperationCanceledException();
|
||||
case UniTaskStatus.Pending:
|
||||
case UniTaskStatus.Succeeded:
|
||||
default:
|
||||
return value;
|
||||
}
|
||||
}
|
||||
|
||||
public void OnCompleted(Action continuation)
|
||||
{
|
||||
ThreadPool.UnsafeQueueUserWorkItem(ThreadPoolWorkItem.Create(continuation), false);
|
||||
}
|
||||
|
||||
public void UnsafeOnCompleted(Action continuation)
|
||||
{
|
||||
ThreadPool.UnsafeQueueUserWorkItem(ThreadPoolWorkItem.Create(continuation), false);
|
||||
}
|
||||
}
|
||||
|
||||
public sealed class ThreadPoolWorkItem : IThreadPoolWorkItem
|
||||
{
|
||||
static readonly ConcurrentQueue<ThreadPoolWorkItem> pool = new ConcurrentQueue<ThreadPoolWorkItem>();
|
||||
|
||||
Action continuation;
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static ThreadPoolWorkItem Create(Action continuation)
|
||||
{
|
||||
if (!pool.TryDequeue(out var item))
|
||||
{
|
||||
item = new ThreadPoolWorkItem();
|
||||
}
|
||||
|
||||
item.continuation = continuation;
|
||||
return item;
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public void Execute()
|
||||
{
|
||||
var call = continuation;
|
||||
continuation = null;
|
||||
pool.Enqueue(this);
|
||||
|
||||
call.Invoke();
|
||||
}
|
||||
}
|
||||
283
src/UniTask.NetCoreSandbox/Benchmark.cs
Normal file
283
src/UniTask.NetCoreSandbox/Benchmark.cs
Normal file
@@ -0,0 +1,283 @@
|
||||
using BenchmarkDotNet.Attributes;
|
||||
using System.Linq;
|
||||
using BenchmarkDotNet.Configs;
|
||||
using BenchmarkDotNet.Diagnosers;
|
||||
using BenchmarkDotNet.Exporters;
|
||||
using BenchmarkDotNet.Jobs;
|
||||
using BenchmarkDotNet.Running;
|
||||
using Cysharp.Threading.Tasks;
|
||||
using PooledAwait;
|
||||
using System;
|
||||
using System.Runtime.ExceptionServices;
|
||||
using System.Threading.Tasks;
|
||||
using System.Threading;
|
||||
using System.Runtime.CompilerServices;
|
||||
using Cysharp.Threading.Tasks.CompilerServices;
|
||||
|
||||
//class Program
|
||||
//{
|
||||
// static void Main(string[] args)
|
||||
// {
|
||||
// var switcher = new BenchmarkSwitcher(new[]
|
||||
// {
|
||||
// typeof(StandardBenchmark)
|
||||
// });
|
||||
|
||||
//#if DEBUG
|
||||
// var b = new StandardBenchmark();
|
||||
|
||||
//#else
|
||||
// switcher.Run(args);
|
||||
//#endif
|
||||
// }
|
||||
//}
|
||||
|
||||
public class BenchmarkConfig : ManualConfig
|
||||
{
|
||||
public BenchmarkConfig()
|
||||
{
|
||||
AddDiagnoser(MemoryDiagnoser.Default);
|
||||
AddJob(Job.ShortRun.WithLaunchCount(1).WithIterationCount(1).WithWarmupCount(1));
|
||||
}
|
||||
}
|
||||
|
||||
// borrowed from PooledAwait
|
||||
|
||||
[Config(typeof(BenchmarkConfig))]
|
||||
[GroupBenchmarksBy(BenchmarkLogicalGroupRule.ByCategory)]
|
||||
[CategoriesColumn]
|
||||
public class ComparisonBenchmarks
|
||||
{
|
||||
// note: all the benchmarks use Task/Task<T> for the public API, because BenchmarkDotNet
|
||||
// doesn't work reliably with more exotic task-types (even just ValueTask fails); instead,
|
||||
// we'll obscure the cost of the outer awaitable by doing a relatively large number of
|
||||
// iterations, so that we're only really measuring the inner loop
|
||||
private const int InnerOps = 1000;
|
||||
|
||||
public bool ConfigureAwait { get; set; } = false;
|
||||
|
||||
[Benchmark(OperationsPerInvoke = InnerOps, Description = ".NET")]
|
||||
[BenchmarkCategory("Task<T>")]
|
||||
public async Task<int> ViaTaskT()
|
||||
{
|
||||
int sum = 0;
|
||||
for (int i = 0; i < InnerOps; i++)
|
||||
sum += await Inner(1, 2).ConfigureAwait(ConfigureAwait);
|
||||
return sum;
|
||||
|
||||
static async Task<int> Inner(int x, int y)
|
||||
{
|
||||
int i = x;
|
||||
await Task.Yield();
|
||||
i *= y;
|
||||
await Task.Yield();
|
||||
return 5 * i;
|
||||
}
|
||||
}
|
||||
|
||||
[Benchmark(OperationsPerInvoke = InnerOps, Description = ".NET")]
|
||||
[BenchmarkCategory("Task")]
|
||||
public async Task ViaTask()
|
||||
{
|
||||
for (int i = 0; i < InnerOps; i++)
|
||||
await Inner().ConfigureAwait(ConfigureAwait);
|
||||
|
||||
static async Task Inner()
|
||||
{
|
||||
await Task.Yield();
|
||||
await Task.Yield();
|
||||
}
|
||||
}
|
||||
|
||||
[Benchmark(OperationsPerInvoke = InnerOps, Description = ".NET")]
|
||||
[BenchmarkCategory("ValueTask<T>")]
|
||||
public async Task<int> ViaValueTaskT()
|
||||
{
|
||||
int sum = 0;
|
||||
for (int i = 0; i < InnerOps; i++)
|
||||
sum += await Inner(1, 2).ConfigureAwait(ConfigureAwait);
|
||||
return sum;
|
||||
|
||||
static async ValueTask<int> Inner(int x, int y)
|
||||
{
|
||||
int i = x;
|
||||
await Task.Yield();
|
||||
i *= y;
|
||||
await Task.Yield();
|
||||
return 5 * i;
|
||||
}
|
||||
}
|
||||
|
||||
[Benchmark(OperationsPerInvoke = InnerOps, Description = ".NET")]
|
||||
[BenchmarkCategory("ValueTask")]
|
||||
public async Task ViaValueTask()
|
||||
{
|
||||
for (int i = 0; i < InnerOps; i++)
|
||||
await Inner().ConfigureAwait(ConfigureAwait);
|
||||
|
||||
static async ValueTask Inner()
|
||||
{
|
||||
await Task.Yield();
|
||||
await Task.Yield();
|
||||
}
|
||||
}
|
||||
|
||||
[Benchmark(OperationsPerInvoke = InnerOps, Description = "Pooled")]
|
||||
[BenchmarkCategory("ValueTask<T>")]
|
||||
public async Task<int> ViaPooledValueTaskT()
|
||||
{
|
||||
int sum = 0;
|
||||
for (int i = 0; i < InnerOps; i++)
|
||||
sum += await Inner(1, 2).ConfigureAwait(ConfigureAwait);
|
||||
return sum;
|
||||
|
||||
static async PooledValueTask<int> Inner(int x, int y)
|
||||
{
|
||||
int i = x;
|
||||
await Task.Yield();
|
||||
i *= y;
|
||||
await Task.Yield();
|
||||
return 5 * i;
|
||||
}
|
||||
}
|
||||
|
||||
[Benchmark(OperationsPerInvoke = InnerOps, Description = "Pooled")]
|
||||
[BenchmarkCategory("ValueTask")]
|
||||
public async Task ViaPooledValueTask()
|
||||
{
|
||||
for (int i = 0; i < InnerOps; i++)
|
||||
await Inner().ConfigureAwait(ConfigureAwait);
|
||||
|
||||
static async PooledValueTask Inner()
|
||||
{
|
||||
await Task.Yield();
|
||||
await Task.Yield();
|
||||
}
|
||||
}
|
||||
|
||||
[Benchmark(OperationsPerInvoke = InnerOps, Description = "Pooled")]
|
||||
[BenchmarkCategory("Task<T>")]
|
||||
public async Task<int> ViaPooledTaskT()
|
||||
{
|
||||
int sum = 0;
|
||||
for (int i = 0; i < InnerOps; i++)
|
||||
sum += await Inner(1, 2).ConfigureAwait(ConfigureAwait);
|
||||
return sum;
|
||||
|
||||
static async PooledTask<int> Inner(int x, int y)
|
||||
{
|
||||
int i = x;
|
||||
await Task.Yield();
|
||||
i *= y;
|
||||
await Task.Yield();
|
||||
return 5 * i;
|
||||
}
|
||||
}
|
||||
|
||||
[Benchmark(OperationsPerInvoke = InnerOps, Description = "Pooled")]
|
||||
[BenchmarkCategory("Task")]
|
||||
public async Task ViaPooledTask()
|
||||
{
|
||||
for (int i = 0; i < InnerOps; i++)
|
||||
await Inner().ConfigureAwait(ConfigureAwait);
|
||||
|
||||
static async PooledTask Inner()
|
||||
{
|
||||
await Task.Yield();
|
||||
await Task.Yield();
|
||||
}
|
||||
}
|
||||
|
||||
// ---
|
||||
|
||||
//[Benchmark(OperationsPerInvoke = InnerOps, Description = "UniTaskVoid")]
|
||||
//[BenchmarkCategory("UniTask")]
|
||||
//public async Task ViaUniTaskVoid()
|
||||
//{
|
||||
// for (int i = 0; i < InnerOps; i++)
|
||||
// {
|
||||
// await Inner();
|
||||
// }
|
||||
|
||||
// static async UniTaskVoid Inner()
|
||||
// {
|
||||
// await UniTask.Yield();
|
||||
// await UniTask.Yield();
|
||||
// }
|
||||
//}
|
||||
|
||||
[Benchmark(OperationsPerInvoke = InnerOps, Description = "UniTask")]
|
||||
[BenchmarkCategory("UniTask")]
|
||||
public async Task ViaUniTask()
|
||||
{
|
||||
for (int i = 0; i < InnerOps; i++)
|
||||
{
|
||||
await Inner();
|
||||
}
|
||||
|
||||
static async UniTask Inner()
|
||||
{
|
||||
await UniTask.Yield();
|
||||
await UniTask.Yield();
|
||||
}
|
||||
}
|
||||
|
||||
[Benchmark(OperationsPerInvoke = InnerOps, Description = "UniTaskT")]
|
||||
[BenchmarkCategory("UniTask")]
|
||||
public async Task<int> ViaUniTaskT()
|
||||
{
|
||||
var sum = 0;
|
||||
for (int i = 0; i < InnerOps; i++)
|
||||
{
|
||||
sum += await Inner(1, 2);
|
||||
}
|
||||
return sum;
|
||||
|
||||
static async UniTask<int> Inner(int x, int y)
|
||||
{
|
||||
int i = x;
|
||||
await UniTask.Yield();
|
||||
i *= y;
|
||||
await UniTask.Yield();
|
||||
return 5 * i;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public struct MyAwaiter : ICriticalNotifyCompletion
|
||||
{
|
||||
public MyAwaiter GetAwaiter() => this;
|
||||
|
||||
public bool IsCompleted => false;
|
||||
|
||||
public void GetResult()
|
||||
{
|
||||
}
|
||||
|
||||
public void OnCompleted(Action continuation)
|
||||
{
|
||||
continuation();
|
||||
}
|
||||
|
||||
public void UnsafeOnCompleted(Action continuation)
|
||||
{
|
||||
continuation();
|
||||
}
|
||||
}
|
||||
|
||||
public struct MyTestStateMachine : IAsyncStateMachine
|
||||
{
|
||||
public void MoveNext()
|
||||
{
|
||||
//throw new NotImplementedException();
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
public void SetStateMachine(IAsyncStateMachine stateMachine)
|
||||
{
|
||||
//throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
@@ -21,6 +21,113 @@ namespace NetCoreSandbox
|
||||
public string text { get; set; }
|
||||
}
|
||||
|
||||
public class ZeroAllocAsyncAwaitInDotNetCore
|
||||
{
|
||||
public ValueTask<int> NanikaAsync(int x, int y)
|
||||
{
|
||||
return Core(this, x, y);
|
||||
|
||||
static async UniTask<int> Core(ZeroAllocAsyncAwaitInDotNetCore self, int x, int y)
|
||||
{
|
||||
// nanika suru...
|
||||
await Task.Delay(TimeSpan.FromSeconds(x + y));
|
||||
|
||||
return 10;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public class TaskTestException : Exception
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
|
||||
public struct TestAwaiter : ICriticalNotifyCompletion
|
||||
{
|
||||
readonly UniTaskStatus status;
|
||||
readonly bool isCompleted;
|
||||
|
||||
public TestAwaiter(bool isCompleted, UniTaskStatus status)
|
||||
{
|
||||
this.isCompleted = isCompleted;
|
||||
this.status = status;
|
||||
}
|
||||
|
||||
public TestAwaiter GetAwaiter() => this;
|
||||
|
||||
public bool IsCompleted => isCompleted;
|
||||
|
||||
public void GetResult()
|
||||
{
|
||||
switch (status)
|
||||
{
|
||||
case UniTaskStatus.Faulted:
|
||||
throw new TaskTestException();
|
||||
case UniTaskStatus.Canceled:
|
||||
throw new OperationCanceledException();
|
||||
case UniTaskStatus.Pending:
|
||||
case UniTaskStatus.Succeeded:
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
public void OnCompleted(Action continuation)
|
||||
{
|
||||
ThreadPool.QueueUserWorkItem(_ => continuation(), null);
|
||||
}
|
||||
|
||||
public void UnsafeOnCompleted(Action continuation)
|
||||
{
|
||||
ThreadPool.UnsafeQueueUserWorkItem(_ => continuation(), null);
|
||||
}
|
||||
}
|
||||
public struct TestAwaiter<T> : ICriticalNotifyCompletion
|
||||
{
|
||||
readonly UniTaskStatus status;
|
||||
readonly bool isCompleted;
|
||||
readonly T value;
|
||||
|
||||
public TestAwaiter(bool isCompleted, UniTaskStatus status, T value)
|
||||
{
|
||||
this.isCompleted = isCompleted;
|
||||
this.status = status;
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
public TestAwaiter<T> GetAwaiter() => this;
|
||||
|
||||
public bool IsCompleted => isCompleted;
|
||||
|
||||
public T GetResult()
|
||||
{
|
||||
switch (status)
|
||||
{
|
||||
case UniTaskStatus.Faulted:
|
||||
throw new TaskTestException();
|
||||
case UniTaskStatus.Canceled:
|
||||
throw new OperationCanceledException();
|
||||
case UniTaskStatus.Pending:
|
||||
case UniTaskStatus.Succeeded:
|
||||
default:
|
||||
return value;
|
||||
}
|
||||
}
|
||||
|
||||
public void OnCompleted(Action continuation)
|
||||
{
|
||||
ThreadPool.QueueUserWorkItem(_ => continuation(), null);
|
||||
}
|
||||
|
||||
public void UnsafeOnCompleted(Action continuation)
|
||||
{
|
||||
ThreadPool.UnsafeQueueUserWorkItem(_ => continuation(), null);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public static partial class UnityUIComponentExtensions
|
||||
{
|
||||
public static void BindTo(this IUniTaskAsyncEnumerable<string> source, Text text)
|
||||
@@ -88,26 +195,47 @@ namespace NetCoreSandbox
|
||||
|
||||
|
||||
|
||||
static void Main(string[] args)
|
||||
static async Task Main(string[] args)
|
||||
{
|
||||
#if !DEBUG
|
||||
BenchmarkDotNet.Running.BenchmarkSwitcher.FromAssembly(typeof(Program).Assembly).Run(args);
|
||||
|
||||
var channel = Channel.CreateSingleConsumerUnbounded<int>();
|
||||
|
||||
// Observable.Range(1,10).CombineLatest(
|
||||
|
||||
var cts = new CancellationTokenSource();
|
||||
|
||||
var token = cts.Token;
|
||||
|
||||
FooAsync(token).ForEachAsync(x => { }, token);
|
||||
//await new ComparisonBenchmarks().ViaUniTaskT();
|
||||
return;
|
||||
#endif
|
||||
|
||||
|
||||
// Observable.Range(1,10).CombineLatest(
|
||||
AsyncTest().Forget();
|
||||
|
||||
|
||||
//AsyncTest().Forget();
|
||||
|
||||
// AsyncTest().Forget();
|
||||
|
||||
|
||||
await UniTask.Yield();
|
||||
Console.ReadLine();
|
||||
}
|
||||
|
||||
#pragma warning disable CS1998
|
||||
|
||||
|
||||
static async UniTaskVoid AsyncTest()
|
||||
{
|
||||
// empty
|
||||
await new TestAwaiter(false, UniTaskStatus.Succeeded);
|
||||
await new TestAwaiter(true, UniTaskStatus.Succeeded);
|
||||
await new TestAwaiter(false, UniTaskStatus.Succeeded);
|
||||
|
||||
|
||||
Console.WriteLine("foo");
|
||||
//return 10;
|
||||
}
|
||||
|
||||
|
||||
|
||||
#pragma warning restore CS1998
|
||||
|
||||
void Foo()
|
||||
{
|
||||
|
||||
|
||||
@@ -7,6 +7,8 @@
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="BenchmarkDotNet" Version="0.12.1" />
|
||||
<PackageReference Include="PooledAwait" Version="1.0.49" />
|
||||
<PackageReference Include="System.Interactive.Async" Version="4.1.1" />
|
||||
<PackageReference Include="System.Reactive" Version="4.4.1" />
|
||||
</ItemGroup>
|
||||
|
||||
301
src/UniTask.NetCoreTests/TaskBuilderCases.cs
Normal file
301
src/UniTask.NetCoreTests/TaskBuilderCases.cs
Normal file
@@ -0,0 +1,301 @@
|
||||
#pragma warning disable CS1998
|
||||
|
||||
using Cysharp.Threading.Tasks;
|
||||
using FluentAssertions;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
using System.Threading.Channels;
|
||||
using Cysharp.Threading.Tasks.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using Xunit;
|
||||
using System.Runtime.CompilerServices;
|
||||
|
||||
namespace NetCoreTests
|
||||
{
|
||||
public class UniTaskBuilderTest
|
||||
{
|
||||
[Fact]
|
||||
public async Task Empty()
|
||||
{
|
||||
await Core();
|
||||
|
||||
static async UniTask Core()
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task EmptyThrow()
|
||||
{
|
||||
await Assert.ThrowsAsync<TaskTestException>(async () => await Core());
|
||||
|
||||
static async UniTask Core()
|
||||
{
|
||||
throw new TaskTestException();
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task Task_Done()
|
||||
{
|
||||
await Core();
|
||||
|
||||
static async UniTask Core()
|
||||
{
|
||||
await new TestAwaiter(true, UniTaskStatus.Succeeded);
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task Task_Fail()
|
||||
{
|
||||
await Assert.ThrowsAsync<TaskTestException>(async () => await Core());
|
||||
|
||||
static async UniTask Core()
|
||||
{
|
||||
await new TestAwaiter(true, UniTaskStatus.Faulted);
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task Task_Cancel()
|
||||
{
|
||||
await Assert.ThrowsAsync<OperationCanceledException>(async () => await Core());
|
||||
|
||||
static async UniTask Core()
|
||||
{
|
||||
await new TestAwaiter(true, UniTaskStatus.Canceled);
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task AwaitUnsafeOnCompletedCall_Task_SetResult()
|
||||
{
|
||||
await Core();
|
||||
|
||||
static async UniTask Core()
|
||||
{
|
||||
await new TestAwaiter(false, UniTaskStatus.Succeeded);
|
||||
await new TestAwaiter(false, UniTaskStatus.Succeeded);
|
||||
await new TestAwaiter(false, UniTaskStatus.Succeeded);
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task AwaitUnsafeOnCompletedCall_Task_SetException()
|
||||
{
|
||||
await Assert.ThrowsAsync<TaskTestException>(async () => await Core());
|
||||
|
||||
static async UniTask Core()
|
||||
{
|
||||
await new TestAwaiter(false, UniTaskStatus.Succeeded);
|
||||
await new TestAwaiter(false, UniTaskStatus.Faulted);
|
||||
throw new InvalidOperationException();
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task AwaitUnsafeOnCompletedCall_Task_SetCancelException()
|
||||
{
|
||||
await Assert.ThrowsAsync<OperationCanceledException>(async () => await Core());
|
||||
|
||||
static async UniTask Core()
|
||||
{
|
||||
await new TestAwaiter(false, UniTaskStatus.Succeeded);
|
||||
await new TestAwaiter(false, UniTaskStatus.Canceled);
|
||||
throw new InvalidOperationException();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public class UniTask_T_BuilderTest
|
||||
{
|
||||
[Fact]
|
||||
public async Task Empty()
|
||||
{
|
||||
(await Core()).Should().Be(10);
|
||||
|
||||
static async UniTask<int> Core()
|
||||
{
|
||||
return 10;
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task EmptyThrow()
|
||||
{
|
||||
await Assert.ThrowsAsync<TaskTestException>(async () => await Core());
|
||||
|
||||
static async UniTask<int> Core()
|
||||
{
|
||||
throw new TaskTestException();
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task Task_Done()
|
||||
{
|
||||
(await Core()).Should().Be(10);
|
||||
|
||||
static async UniTask<int> Core()
|
||||
{
|
||||
return await new TestAwaiter<int>(true, UniTaskStatus.Succeeded, 10);
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task Task_Fail()
|
||||
{
|
||||
await Assert.ThrowsAsync<TaskTestException>(async () => await Core());
|
||||
|
||||
static async UniTask<int> Core()
|
||||
{
|
||||
return await new TestAwaiter<int>(true, UniTaskStatus.Faulted, 10);
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task Task_Cancel()
|
||||
{
|
||||
await Assert.ThrowsAsync<OperationCanceledException>(async () => await Core());
|
||||
|
||||
static async UniTask<int> Core()
|
||||
{
|
||||
return await new TestAwaiter<int>(true, UniTaskStatus.Canceled, 10);
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task AwaitUnsafeOnCompletedCall_Task_SetResult()
|
||||
{
|
||||
(await Core()).Should().Be(6);
|
||||
|
||||
static async UniTask<int> Core()
|
||||
{
|
||||
var sum = 0;
|
||||
sum += await new TestAwaiter<int>(false, UniTaskStatus.Succeeded, 1);
|
||||
sum += await new TestAwaiter<int>(false, UniTaskStatus.Succeeded, 2);
|
||||
sum += await new TestAwaiter<int>(false, UniTaskStatus.Succeeded, 3);
|
||||
return sum;
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task AwaitUnsafeOnCompletedCall_Task_SetException()
|
||||
{
|
||||
await Assert.ThrowsAsync<TaskTestException>(async () => await Core());
|
||||
|
||||
static async UniTask<int> Core()
|
||||
{
|
||||
await new TestAwaiter<int>(false, UniTaskStatus.Succeeded, 10);
|
||||
await new TestAwaiter<int>(false, UniTaskStatus.Faulted, 10);
|
||||
throw new InvalidOperationException();
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task AwaitUnsafeOnCompletedCall_Task_SetCancelException()
|
||||
{
|
||||
await Assert.ThrowsAsync<OperationCanceledException>(async () => await Core());
|
||||
|
||||
static async UniTask<int> Core()
|
||||
{
|
||||
await new TestAwaiter<int>(false, UniTaskStatus.Succeeded, 10);
|
||||
await new TestAwaiter<int>(false, UniTaskStatus.Canceled, 10);
|
||||
throw new InvalidOperationException();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public class TaskTestException : Exception
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public struct TestAwaiter : ICriticalNotifyCompletion
|
||||
{
|
||||
readonly UniTaskStatus status;
|
||||
readonly bool isCompleted;
|
||||
|
||||
public TestAwaiter(bool isCompleted, UniTaskStatus status)
|
||||
{
|
||||
this.isCompleted = isCompleted;
|
||||
this.status = status;
|
||||
}
|
||||
|
||||
public TestAwaiter GetAwaiter() => this;
|
||||
|
||||
public bool IsCompleted => isCompleted;
|
||||
|
||||
public void GetResult()
|
||||
{
|
||||
switch (status)
|
||||
{
|
||||
case UniTaskStatus.Faulted:
|
||||
throw new TaskTestException();
|
||||
case UniTaskStatus.Canceled:
|
||||
throw new OperationCanceledException();
|
||||
case UniTaskStatus.Pending:
|
||||
case UniTaskStatus.Succeeded:
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
public void OnCompleted(Action continuation)
|
||||
{
|
||||
ThreadPool.QueueUserWorkItem(_ => continuation(), null);
|
||||
}
|
||||
|
||||
public void UnsafeOnCompleted(Action continuation)
|
||||
{
|
||||
ThreadPool.UnsafeQueueUserWorkItem(_ => continuation(), null);
|
||||
}
|
||||
}
|
||||
|
||||
public struct TestAwaiter<T> : ICriticalNotifyCompletion
|
||||
{
|
||||
readonly UniTaskStatus status;
|
||||
readonly bool isCompleted;
|
||||
readonly T value;
|
||||
|
||||
public TestAwaiter(bool isCompleted, UniTaskStatus status, T value)
|
||||
{
|
||||
this.isCompleted = isCompleted;
|
||||
this.status = status;
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
public TestAwaiter<T> GetAwaiter() => this;
|
||||
|
||||
public bool IsCompleted => isCompleted;
|
||||
|
||||
public T GetResult()
|
||||
{
|
||||
switch (status)
|
||||
{
|
||||
case UniTaskStatus.Faulted:
|
||||
throw new TaskTestException();
|
||||
case UniTaskStatus.Canceled:
|
||||
throw new OperationCanceledException();
|
||||
case UniTaskStatus.Pending:
|
||||
case UniTaskStatus.Succeeded:
|
||||
default:
|
||||
return value;
|
||||
}
|
||||
}
|
||||
|
||||
public void OnCompleted(Action continuation)
|
||||
{
|
||||
ThreadPool.QueueUserWorkItem(_ => continuation(), null);
|
||||
}
|
||||
|
||||
public void UnsafeOnCompleted(Action continuation)
|
||||
{
|
||||
ThreadPool.UnsafeQueueUserWorkItem(_ => continuation(), null);
|
||||
}
|
||||
}
|
||||
}
|
||||
30
src/UniTask/Assets/Editor/EditorRunnerChecker.cs
Normal file
30
src/UniTask/Assets/Editor/EditorRunnerChecker.cs
Normal file
@@ -0,0 +1,30 @@
|
||||
#if UNITY_EDITOR
|
||||
|
||||
using Cysharp.Threading.Tasks;
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
using UnityEngine.Networking;
|
||||
|
||||
public static class EditorRunnerChecker
|
||||
{
|
||||
[MenuItem("Tools/UniTaskEditorRunnerChecker")]
|
||||
public static void RunUniTaskAsync()
|
||||
{
|
||||
RunCore().Forget();
|
||||
}
|
||||
|
||||
static async UniTaskVoid RunCore()
|
||||
{
|
||||
Debug.Log("Start");
|
||||
|
||||
var r = await UnityWebRequest.Get("https://bing.com/").SendWebRequest().ToUniTask();
|
||||
Debug.Log(r.downloadHandler.text.Substring(0, 100));
|
||||
|
||||
Debug.Log("End");
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
11
src/UniTask/Assets/Editor/EditorRunnerChecker.cs.meta
Normal file
11
src/UniTask/Assets/Editor/EditorRunnerChecker.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: e51b78c06cb410f42b36e0af9de3b065
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -4,7 +4,7 @@ using System;
|
||||
|
||||
namespace Cysharp.Threading.Tasks
|
||||
{
|
||||
public struct AsyncUnit : IEquatable<AsyncUnit>
|
||||
public readonly struct AsyncUnit : IEquatable<AsyncUnit>
|
||||
{
|
||||
public static readonly AsyncUnit Default = new AsyncUnit();
|
||||
|
||||
|
||||
@@ -368,8 +368,8 @@ namespace Cysharp.Threading.Tasks
|
||||
readonly SingleConsumerUnboundedChannelReader parent;
|
||||
CancellationToken cancellationToken1;
|
||||
CancellationToken cancellationToken2;
|
||||
CancellationTokenRegistration CancellationTokenRegistration1;
|
||||
CancellationTokenRegistration CancellationTokenRegistration2;
|
||||
CancellationTokenRegistration cancellationTokenRegistration1;
|
||||
CancellationTokenRegistration cancellationTokenRegistration2;
|
||||
|
||||
T current;
|
||||
bool cacheValue;
|
||||
@@ -395,12 +395,12 @@ namespace Cysharp.Threading.Tasks
|
||||
|
||||
if (this.cancellationToken1.CanBeCanceled)
|
||||
{
|
||||
this.cancellationToken1.RegisterWithoutCaptureExecutionContext(CancellationCallback1Delegate, this);
|
||||
this.cancellationTokenRegistration1 = this.cancellationToken1.RegisterWithoutCaptureExecutionContext(CancellationCallback1Delegate, this);
|
||||
}
|
||||
|
||||
if (this.cancellationToken2.CanBeCanceled)
|
||||
{
|
||||
this.cancellationToken2.RegisterWithoutCaptureExecutionContext(CancellationCallback2Delegate, this);
|
||||
this.cancellationTokenRegistration2 = this.cancellationToken2.RegisterWithoutCaptureExecutionContext(CancellationCallback2Delegate, this);
|
||||
}
|
||||
|
||||
running = true;
|
||||
@@ -428,8 +428,8 @@ namespace Cysharp.Threading.Tasks
|
||||
|
||||
public UniTask DisposeAsync()
|
||||
{
|
||||
CancellationTokenRegistration1.Dispose();
|
||||
CancellationTokenRegistration2.Dispose();
|
||||
cancellationTokenRegistration1.Dispose();
|
||||
cancellationTokenRegistration2.Dispose();
|
||||
return default;
|
||||
}
|
||||
|
||||
|
||||
@@ -14,7 +14,7 @@ namespace Cysharp.Threading.Tasks.CompilerServices
|
||||
{
|
||||
// cache items.
|
||||
AutoResetUniTaskCompletionSource promise;
|
||||
IMoveNextRunner runner;
|
||||
internal IMoveNextRunner runner;
|
||||
|
||||
// 1. Static Create method.
|
||||
[DebuggerHidden]
|
||||
@@ -50,6 +50,8 @@ 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)
|
||||
{
|
||||
@@ -57,9 +59,9 @@ namespace Cysharp.Threading.Tasks.CompilerServices
|
||||
runner = null;
|
||||
}
|
||||
|
||||
if (promise != null)
|
||||
if (p != null)
|
||||
{
|
||||
promise.TrySetException(exception);
|
||||
p.TrySetException(exception);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -71,6 +73,8 @@ 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)
|
||||
{
|
||||
@@ -78,9 +82,9 @@ namespace Cysharp.Threading.Tasks.CompilerServices
|
||||
runner = null;
|
||||
}
|
||||
|
||||
if (promise != null)
|
||||
if (p != null)
|
||||
{
|
||||
promise.TrySetResult();
|
||||
p.TrySetResult();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -96,7 +100,7 @@ namespace Cysharp.Threading.Tasks.CompilerServices
|
||||
}
|
||||
if (runner == null)
|
||||
{
|
||||
runner = MoveNextRunner<TStateMachine>.Create(ref stateMachine);
|
||||
MoveNextRunner<TStateMachine>.SetRunner(ref this, ref stateMachine);
|
||||
}
|
||||
|
||||
awaiter.OnCompleted(runner.CallMoveNext);
|
||||
@@ -115,10 +119,10 @@ namespace Cysharp.Threading.Tasks.CompilerServices
|
||||
}
|
||||
if (runner == null)
|
||||
{
|
||||
runner = MoveNextRunner<TStateMachine>.Create(ref stateMachine);
|
||||
MoveNextRunner<TStateMachine>.SetRunner(ref this, ref stateMachine);
|
||||
}
|
||||
|
||||
awaiter.OnCompleted(runner.CallMoveNext);
|
||||
awaiter.UnsafeOnCompleted(runner.CallMoveNext);
|
||||
}
|
||||
|
||||
// 7. Start
|
||||
@@ -158,7 +162,7 @@ namespace Cysharp.Threading.Tasks.CompilerServices
|
||||
{
|
||||
// cache items.
|
||||
AutoResetUniTaskCompletionSource<T> promise;
|
||||
IMoveNextRunner runner;
|
||||
internal IMoveNextRunner runner;
|
||||
T result;
|
||||
|
||||
// 1. Static Create method.
|
||||
@@ -194,6 +198,8 @@ 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)
|
||||
{
|
||||
@@ -201,13 +207,13 @@ namespace Cysharp.Threading.Tasks.CompilerServices
|
||||
runner = null;
|
||||
}
|
||||
|
||||
if (promise == null)
|
||||
if (p == null)
|
||||
{
|
||||
promise = AutoResetUniTaskCompletionSource<T>.CreateFromException(exception, out _);
|
||||
}
|
||||
else
|
||||
{
|
||||
promise.TrySetException(exception);
|
||||
p.TrySetException(exception);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -215,6 +221,8 @@ 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)
|
||||
{
|
||||
@@ -222,13 +230,14 @@ namespace Cysharp.Threading.Tasks.CompilerServices
|
||||
runner = null;
|
||||
}
|
||||
|
||||
if (promise == null)
|
||||
if (p == null)
|
||||
{
|
||||
this.result = result;
|
||||
return;
|
||||
}
|
||||
|
||||
promise.TrySetResult(result);
|
||||
else
|
||||
{
|
||||
p.TrySetResult(result);
|
||||
}
|
||||
}
|
||||
|
||||
// 5. AwaitOnCompleted
|
||||
@@ -243,7 +252,7 @@ namespace Cysharp.Threading.Tasks.CompilerServices
|
||||
}
|
||||
if (runner == null)
|
||||
{
|
||||
runner = MoveNextRunner<TStateMachine>.Create(ref stateMachine);
|
||||
MoveNextRunner<TStateMachine>.SetRunner(ref this, ref stateMachine);
|
||||
}
|
||||
|
||||
awaiter.OnCompleted(runner.CallMoveNext);
|
||||
@@ -262,10 +271,10 @@ namespace Cysharp.Threading.Tasks.CompilerServices
|
||||
}
|
||||
if (runner == null)
|
||||
{
|
||||
runner = MoveNextRunner<TStateMachine>.Create(ref stateMachine);
|
||||
MoveNextRunner<TStateMachine>.SetRunner(ref this, ref stateMachine);
|
||||
}
|
||||
|
||||
awaiter.OnCompleted(runner.CallMoveNext);
|
||||
awaiter.UnsafeOnCompleted(runner.CallMoveNext);
|
||||
}
|
||||
|
||||
// 7. Start
|
||||
|
||||
@@ -10,7 +10,7 @@ namespace Cysharp.Threading.Tasks.CompilerServices
|
||||
{
|
||||
public struct AsyncUniTaskVoidMethodBuilder
|
||||
{
|
||||
IMoveNextRunner runner;
|
||||
internal IMoveNextRunner runner;
|
||||
|
||||
// 1. Static Create method.
|
||||
[DebuggerHidden]
|
||||
@@ -65,7 +65,7 @@ namespace Cysharp.Threading.Tasks.CompilerServices
|
||||
{
|
||||
if (runner == null)
|
||||
{
|
||||
runner = MoveNextRunner<TStateMachine>.Create(ref stateMachine);
|
||||
MoveNextRunner<TStateMachine>.SetRunner(ref this, ref stateMachine);
|
||||
}
|
||||
|
||||
awaiter.OnCompleted(runner.CallMoveNext);
|
||||
@@ -80,10 +80,10 @@ namespace Cysharp.Threading.Tasks.CompilerServices
|
||||
{
|
||||
if (runner == null)
|
||||
{
|
||||
runner = MoveNextRunner<TStateMachine>.Create(ref stateMachine);
|
||||
MoveNextRunner<TStateMachine>.SetRunner(ref this, ref stateMachine);
|
||||
}
|
||||
|
||||
awaiter.OnCompleted(runner.CallMoveNext);
|
||||
awaiter.UnsafeOnCompleted(runner.CallMoveNext);
|
||||
}
|
||||
|
||||
// 7. Start
|
||||
|
||||
@@ -26,19 +26,48 @@ namespace Cysharp.Threading.Tasks.CompilerServices
|
||||
|
||||
MoveNextRunner()
|
||||
{
|
||||
callMoveNext = MoveNext;
|
||||
callMoveNext = Run;
|
||||
}
|
||||
|
||||
public static MoveNextRunner<TStateMachine> Create(ref TStateMachine stateMachine)
|
||||
public static void SetRunner(ref AsyncUniTaskMethodBuilder builder, ref TStateMachine stateMachine)
|
||||
{
|
||||
var result = pool.TryRent() ?? new MoveNextRunner<TStateMachine>();
|
||||
result.stateMachine = stateMachine;
|
||||
return result;
|
||||
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).
|
||||
}
|
||||
|
||||
public static void SetRunner<T>(ref AsyncUniTaskMethodBuilder<T> builder, ref TStateMachine stateMachine)
|
||||
{
|
||||
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).
|
||||
}
|
||||
|
||||
public static void SetRunner(ref AsyncUniTaskVoidMethodBuilder builder, ref TStateMachine stateMachine)
|
||||
{
|
||||
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).
|
||||
}
|
||||
|
||||
[DebuggerHidden]
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
void MoveNext()
|
||||
void Run()
|
||||
{
|
||||
stateMachine.MoveNext();
|
||||
}
|
||||
|
||||
@@ -202,10 +202,10 @@ namespace Cysharp.Threading.Tasks
|
||||
return new UniTask<T>(AsyncOperationHandleConfiguredSource<T>.Create(handle, PlayerLoopTiming.Update, null, cancellationToken, out var token), token);
|
||||
}
|
||||
|
||||
public static UniTask<T> ToUniTask<T>(this AsyncOperationHandle<T> handle, IProgress<float> progress = null, PlayerLoopTiming timing = PlayerLoopTiming.Update, CancellationToken cancellation = default(CancellationToken))
|
||||
public static UniTask<T> ToUniTask<T>(this AsyncOperationHandle<T> handle, IProgress<float> progress = null, PlayerLoopTiming timing = PlayerLoopTiming.Update, CancellationToken cancellationToken = default(CancellationToken))
|
||||
{
|
||||
if (handle.IsDone) return UniTask.FromResult(handle.Result);
|
||||
return new UniTask<T>(AsyncOperationHandleConfiguredSource<T>.Create(handle, timing, progress, cancellation, out var token), token);
|
||||
return new UniTask<T>(AsyncOperationHandleConfiguredSource<T>.Create(handle, timing, progress, cancellationToken, out var token), token);
|
||||
}
|
||||
|
||||
public struct AsyncOperationHandleAwaiter<T> : ICriticalNotifyCompletion
|
||||
|
||||
@@ -33,7 +33,7 @@ namespace Cysharp.Threading.Tasks
|
||||
return new TweenAwaiter(tween);
|
||||
}
|
||||
|
||||
public static UniTask WithCancellation(this Tween tween, CancellationToken cancellationToken = default)
|
||||
public static UniTask WithCancellation(this Tween tween, CancellationToken cancellationToken)
|
||||
{
|
||||
Error.ThrowArgumentNullException(tween, nameof(tween));
|
||||
|
||||
@@ -86,7 +86,8 @@ namespace Cysharp.Threading.Tasks
|
||||
sealed class TweenConfiguredSource : IUniTaskSource, IPromisePoolItem
|
||||
{
|
||||
static readonly PromisePool<TweenConfiguredSource> pool = new PromisePool<TweenConfiguredSource>();
|
||||
static Action<object> CancellationCallbackDelegate = CancellationCallback;
|
||||
static readonly Action<object> CancellationCallbackDelegate = CancellationCallback;
|
||||
static readonly TweenCallback EmptyTweenCallback = () => { };
|
||||
|
||||
Tween tween;
|
||||
TweenCancelBehaviour cancelBehaviour;
|
||||
@@ -138,14 +139,7 @@ namespace Cysharp.Threading.Tasks
|
||||
cancellationTokenRegistration.Dispose();
|
||||
if (canceled)
|
||||
{
|
||||
if (cancelBehaviour == TweenCancelBehaviour.CancelAwait)
|
||||
{
|
||||
// already called TrySetCanceled, do nothing.
|
||||
}
|
||||
else
|
||||
{
|
||||
core.TrySetCanceled(cancellationToken);
|
||||
}
|
||||
core.TrySetCanceled(cancellationToken);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -189,7 +183,7 @@ namespace Cysharp.Threading.Tasks
|
||||
self.tween.Complete(true);
|
||||
break;
|
||||
case TweenCancelBehaviour.CancelAwait:
|
||||
self.canceled = true;
|
||||
self.tween.onKill = EmptyTweenCallback; // replace to empty(avoid callback after Caceled(instance is returned to pool.)
|
||||
self.core.TrySetCanceled(self.cancellationToken);
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -19,17 +19,75 @@ namespace Cysharp.Threading.Tasks
|
||||
|
||||
// similar as IValueTaskSource
|
||||
public interface IUniTaskSource
|
||||
#if !UNITY_2018_3_OR_NEWER
|
||||
: System.Threading.Tasks.Sources.IValueTaskSource
|
||||
#pragma warning disable CS0108
|
||||
#endif
|
||||
{
|
||||
UniTaskStatus GetStatus(short token);
|
||||
void OnCompleted(Action<object> continuation, object state, short token);
|
||||
void GetResult(short token);
|
||||
|
||||
UniTaskStatus UnsafeGetStatus(); // only for debug use.
|
||||
|
||||
#if !UNITY_2018_3_OR_NEWER
|
||||
#pragma warning restore CS0108
|
||||
|
||||
System.Threading.Tasks.Sources.ValueTaskSourceStatus System.Threading.Tasks.Sources.IValueTaskSource.GetStatus(short token)
|
||||
{
|
||||
return (System.Threading.Tasks.Sources.ValueTaskSourceStatus)(int)((IUniTaskSource)this).GetStatus(token);
|
||||
}
|
||||
|
||||
void System.Threading.Tasks.Sources.IValueTaskSource.GetResult(short token)
|
||||
{
|
||||
((IUniTaskSource)this).GetResult(token);
|
||||
}
|
||||
|
||||
void System.Threading.Tasks.Sources.IValueTaskSource.OnCompleted(Action<object> continuation, object state, short token, System.Threading.Tasks.Sources.ValueTaskSourceOnCompletedFlags flags)
|
||||
{
|
||||
// ignore flags, always none.
|
||||
((IUniTaskSource)this).OnCompleted(continuation, state, token);
|
||||
}
|
||||
|
||||
#endif
|
||||
}
|
||||
|
||||
public interface IUniTaskSource<out T> : IUniTaskSource
|
||||
#if !UNITY_2018_3_OR_NEWER
|
||||
, System.Threading.Tasks.Sources.IValueTaskSource<T>
|
||||
#endif
|
||||
{
|
||||
new T GetResult(short token);
|
||||
|
||||
#if !UNITY_2018_3_OR_NEWER
|
||||
|
||||
new public UniTaskStatus GetStatus(short token)
|
||||
{
|
||||
return ((IUniTaskSource)this).GetStatus(token);
|
||||
}
|
||||
|
||||
new public void OnCompleted(Action<object> continuation, object state, short token)
|
||||
{
|
||||
((IUniTaskSource)this).OnCompleted(continuation, state, token);
|
||||
}
|
||||
|
||||
System.Threading.Tasks.Sources.ValueTaskSourceStatus System.Threading.Tasks.Sources.IValueTaskSource<T>.GetStatus(short token)
|
||||
{
|
||||
return (System.Threading.Tasks.Sources.ValueTaskSourceStatus)(int)((IUniTaskSource)this).GetStatus(token);
|
||||
}
|
||||
|
||||
T System.Threading.Tasks.Sources.IValueTaskSource<T>.GetResult(short token)
|
||||
{
|
||||
return ((IUniTaskSource<T>)this).GetResult(token);
|
||||
}
|
||||
|
||||
void System.Threading.Tasks.Sources.IValueTaskSource<T>.OnCompleted(Action<object> continuation, object state, short token, System.Threading.Tasks.Sources.ValueTaskSourceOnCompletedFlags flags)
|
||||
{
|
||||
// ignore flags, always none.
|
||||
((IUniTaskSource)this).OnCompleted(continuation, state, token);
|
||||
}
|
||||
|
||||
#endif
|
||||
}
|
||||
|
||||
public static class UniTaskStatusExtensions
|
||||
|
||||
@@ -200,27 +200,43 @@ namespace Cysharp.Threading.Tasks
|
||||
|
||||
|
||||
#if UNITY_EDITOR
|
||||
|
||||
[InitializeOnLoadMethod]
|
||||
static void InitOnEditor()
|
||||
{
|
||||
//Execute the play mode init method
|
||||
// Execute the play mode init method
|
||||
Init();
|
||||
|
||||
//register an Editor update delegate, used to forcing playerLoop update
|
||||
// register an Editor update delegate, used to forcing playerLoop update
|
||||
EditorApplication.update += ForceEditorPlayerLoopUpdate;
|
||||
}
|
||||
|
||||
private static void ForceEditorPlayerLoopUpdate()
|
||||
{
|
||||
if (EditorApplication.isPlayingOrWillChangePlaymode || EditorApplication.isCompiling ||
|
||||
EditorApplication.isUpdating)
|
||||
if (EditorApplication.isPlayingOrWillChangePlaymode || EditorApplication.isCompiling || EditorApplication.isUpdating)
|
||||
{
|
||||
// Not in Edit mode, don't interfere
|
||||
return;
|
||||
}
|
||||
|
||||
//force unity to update PlayerLoop callbacks
|
||||
EditorApplication.QueuePlayerLoopUpdate();
|
||||
// EditorApplication.QueuePlayerLoopUpdate causes performance issue, don't call directly.
|
||||
// EditorApplication.QueuePlayerLoopUpdate();
|
||||
|
||||
if (yielders != null)
|
||||
{
|
||||
foreach (var item in yielders)
|
||||
{
|
||||
if (item != null) item.Run();
|
||||
}
|
||||
}
|
||||
|
||||
if (runners != null)
|
||||
{
|
||||
foreach (var item in runners)
|
||||
{
|
||||
if (item != null) item.Run();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
@@ -1,13 +1,12 @@
|
||||
#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member
|
||||
#pragma warning disable CS0436
|
||||
|
||||
using Cysharp.Threading.Tasks.CompilerServices;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.ExceptionServices;
|
||||
using Cysharp.Threading.Tasks.CompilerServices;
|
||||
using Cysharp.Threading.Tasks.Internal;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace Cysharp.Threading.Tasks
|
||||
{
|
||||
@@ -26,6 +25,7 @@ namespace Cysharp.Threading.Tasks
|
||||
/// Lightweight unity specified task-like object.
|
||||
/// </summary>
|
||||
[AsyncMethodBuilder(typeof(AsyncUniTaskMethodBuilder))]
|
||||
[StructLayout(LayoutKind.Auto)]
|
||||
public readonly partial struct UniTask
|
||||
{
|
||||
readonly IUniTaskSource source;
|
||||
@@ -68,6 +68,20 @@ namespace Cysharp.Threading.Tasks
|
||||
return new UniTask<bool>(new IsCanceledSource(source), token);
|
||||
}
|
||||
|
||||
#if !UNITY_2018_3_OR_NEWER
|
||||
|
||||
public static implicit operator System.Threading.Tasks.ValueTask(in UniTask self)
|
||||
{
|
||||
if (self.source == null)
|
||||
{
|
||||
return default;
|
||||
}
|
||||
|
||||
return new System.Threading.Tasks.ValueTask(self.source, self.token);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
if (source == null) return "()";
|
||||
@@ -339,6 +353,7 @@ namespace Cysharp.Threading.Tasks
|
||||
/// Lightweight unity specified task-like object.
|
||||
/// </summary>
|
||||
[AsyncMethodBuilder(typeof(AsyncUniTaskMethodBuilder<>))]
|
||||
[StructLayout(LayoutKind.Auto)]
|
||||
public readonly struct UniTask<T>
|
||||
{
|
||||
readonly IUniTaskSource<T> source;
|
||||
@@ -414,6 +429,20 @@ namespace Cysharp.Threading.Tasks
|
||||
return self.AsUniTask();
|
||||
}
|
||||
|
||||
#if !UNITY_2018_3_OR_NEWER
|
||||
|
||||
public static implicit operator System.Threading.Tasks.ValueTask<T>(in UniTask<T> self)
|
||||
{
|
||||
if (self.source == null)
|
||||
{
|
||||
return new System.Threading.Tasks.ValueTask<T>(self.result);
|
||||
}
|
||||
|
||||
return new System.Threading.Tasks.ValueTask<T>(self.source, self.token);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
/// <summary>
|
||||
/// returns (bool IsCanceled, T Result) instead of throws OperationCanceledException.
|
||||
/// </summary>
|
||||
|
||||
@@ -271,7 +271,7 @@ namespace Cysharp.Threading.Tasks
|
||||
{
|
||||
if (token != version)
|
||||
{
|
||||
throw new InvalidOperationException("token version is not matched, can not await twice.");
|
||||
throw new InvalidOperationException("Token version is not matched, can not await twice or get Status after await.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,7 +9,7 @@ namespace Cysharp.Threading.Tasks
|
||||
{
|
||||
public static class UniTaskObservableExtensions
|
||||
{
|
||||
public static UniTask<T> ToUniTask<T>(this IObservable<T> source, CancellationToken cancellationToken = default(CancellationToken), bool useFirstValue = false)
|
||||
public static UniTask<T> ToUniTask<T>(this IObservable<T> source, bool useFirstValue = false, CancellationToken cancellationToken = default)
|
||||
{
|
||||
var promise = new UniTaskCompletionSource<T>();
|
||||
var disposable = new SingleAssignmentDisposable();
|
||||
|
||||
@@ -9,41 +9,41 @@ using Cysharp.Threading.Tasks.CompilerServices;
|
||||
namespace Cysharp.Threading.Tasks
|
||||
{
|
||||
[AsyncMethodBuilder(typeof(AsyncUniTaskVoidMethodBuilder))]
|
||||
public struct UniTaskVoid
|
||||
public readonly struct UniTaskVoid
|
||||
{
|
||||
public void Forget()
|
||||
{
|
||||
}
|
||||
|
||||
[DebuggerHidden]
|
||||
public Awaiter GetAwaiter()
|
||||
{
|
||||
return new Awaiter();
|
||||
}
|
||||
// [DebuggerHidden]
|
||||
// public Awaiter GetAwaiter()
|
||||
// {
|
||||
// return new Awaiter();
|
||||
// }
|
||||
|
||||
public struct Awaiter : ICriticalNotifyCompletion
|
||||
{
|
||||
[DebuggerHidden]
|
||||
public bool IsCompleted => true;
|
||||
// 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 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 OnCompleted(Action continuation)
|
||||
// {
|
||||
// }
|
||||
|
||||
[DebuggerHidden]
|
||||
public void UnsafeOnCompleted(Action continuation)
|
||||
{
|
||||
}
|
||||
}
|
||||
// [DebuggerHidden]
|
||||
// public void UnsafeOnCompleted(Action continuation)
|
||||
// {
|
||||
// }
|
||||
// }
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -9,10 +9,11 @@ namespace Cysharp.Threading.Tasks
|
||||
{
|
||||
public static partial class UnityAsyncExtensions
|
||||
{
|
||||
public static async UniTask WaitAsync(this JobHandle jobHandle, PlayerLoopTiming waitTiming)
|
||||
public static async UniTask WaitAsync(this JobHandle jobHandle, PlayerLoopTiming waitTiming, CancellationToken cancellationToken = default)
|
||||
{
|
||||
await UniTask.Yield(waitTiming);
|
||||
jobHandle.Complete();
|
||||
cancellationToken.ThrowIfCancellationRequested(); // call cancel after Complete.
|
||||
}
|
||||
|
||||
public static UniTask.Awaiter GetAwaiter(this JobHandle jobHandle)
|
||||
@@ -28,7 +29,9 @@ namespace Cysharp.Threading.Tasks
|
||||
|
||||
return new UniTask(handler, token).GetAwaiter();
|
||||
}
|
||||
|
||||
|
||||
// can not pass CancellationToken because can't handle JobHandle's Complete and NativeArray.Dispose.
|
||||
|
||||
public static UniTask ToUniTask(this JobHandle jobHandle, PlayerLoopTiming waitTiming)
|
||||
{
|
||||
var handler = JobHandlePromise.Create(jobHandle, out var token);
|
||||
|
||||
@@ -13,7 +13,7 @@ namespace Cysharp.Threading.Tasks
|
||||
{
|
||||
public static partial class UnityAsyncExtensions
|
||||
{
|
||||
#region AsyncOperation
|
||||
#region AsyncOperation
|
||||
|
||||
public static AsyncOperationAwaiter GetAwaiter(this AsyncOperation asyncOperation)
|
||||
{
|
||||
@@ -116,7 +116,7 @@ namespace Cysharp.Threading.Tasks
|
||||
try
|
||||
{
|
||||
TaskTracker.RemoveTracking(this);
|
||||
|
||||
|
||||
core.GetResult(token);
|
||||
}
|
||||
finally
|
||||
@@ -179,9 +179,9 @@ namespace Cysharp.Threading.Tasks
|
||||
}
|
||||
}
|
||||
|
||||
# endregion
|
||||
#endregion
|
||||
|
||||
#region ResourceRequest
|
||||
#region ResourceRequest
|
||||
|
||||
public static ResourceRequestAwaiter GetAwaiter(this ResourceRequest asyncOperation)
|
||||
{
|
||||
@@ -288,7 +288,7 @@ namespace Cysharp.Threading.Tasks
|
||||
try
|
||||
{
|
||||
TaskTracker.RemoveTracking(this);
|
||||
|
||||
|
||||
return core.GetResult(token);
|
||||
}
|
||||
finally
|
||||
@@ -356,9 +356,9 @@ namespace Cysharp.Threading.Tasks
|
||||
}
|
||||
}
|
||||
|
||||
# endregion
|
||||
#endregion
|
||||
|
||||
#region AssetBundleRequest
|
||||
#region AssetBundleRequest
|
||||
|
||||
public static AssetBundleRequestAwaiter GetAwaiter(this AssetBundleRequest asyncOperation)
|
||||
{
|
||||
@@ -465,7 +465,7 @@ namespace Cysharp.Threading.Tasks
|
||||
try
|
||||
{
|
||||
TaskTracker.RemoveTracking(this);
|
||||
|
||||
|
||||
return core.GetResult(token);
|
||||
}
|
||||
finally
|
||||
@@ -533,9 +533,9 @@ namespace Cysharp.Threading.Tasks
|
||||
}
|
||||
}
|
||||
|
||||
# endregion
|
||||
#endregion
|
||||
|
||||
#region AssetBundleCreateRequest
|
||||
#region AssetBundleCreateRequest
|
||||
|
||||
public static AssetBundleCreateRequestAwaiter GetAwaiter(this AssetBundleCreateRequest asyncOperation)
|
||||
{
|
||||
@@ -642,7 +642,7 @@ namespace Cysharp.Threading.Tasks
|
||||
try
|
||||
{
|
||||
TaskTracker.RemoveTracking(this);
|
||||
|
||||
|
||||
return core.GetResult(token);
|
||||
}
|
||||
finally
|
||||
@@ -710,10 +710,10 @@ namespace Cysharp.Threading.Tasks
|
||||
}
|
||||
}
|
||||
|
||||
# endregion
|
||||
#endregion
|
||||
|
||||
#if ENABLE_UNITYWEBREQUEST
|
||||
#region UnityWebRequestAsyncOperation
|
||||
#region UnityWebRequestAsyncOperation
|
||||
|
||||
public static UnityWebRequestAsyncOperationAwaiter GetAwaiter(this UnityWebRequestAsyncOperation asyncOperation)
|
||||
{
|
||||
@@ -820,7 +820,7 @@ namespace Cysharp.Threading.Tasks
|
||||
try
|
||||
{
|
||||
TaskTracker.RemoveTracking(this);
|
||||
|
||||
|
||||
return core.GetResult(token);
|
||||
}
|
||||
finally
|
||||
@@ -853,6 +853,7 @@ namespace Cysharp.Threading.Tasks
|
||||
{
|
||||
if (cancellationToken.IsCancellationRequested)
|
||||
{
|
||||
asyncOperation.webRequest.Abort();
|
||||
core.TrySetCanceled(cancellationToken);
|
||||
return false;
|
||||
}
|
||||
@@ -888,7 +889,7 @@ namespace Cysharp.Threading.Tasks
|
||||
}
|
||||
}
|
||||
|
||||
# endregion
|
||||
#endregion
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
{
|
||||
"name": "com.cysharp.unitask",
|
||||
"displayName": "UniTask",
|
||||
"version": "2.0.10-rc7",
|
||||
"unity": "2018.3",
|
||||
"version": "2.0.11-rc8",
|
||||
"unity": "2019.1",
|
||||
"description": "Provides an efficient async/await integration to Unity.",
|
||||
"keywords": [ "async/await", "async", "Task", "UniTask" ],
|
||||
"license": "MIT",
|
||||
|
||||
@@ -10,6 +10,7 @@ using System.Threading.Tasks;
|
||||
using Unity.Collections;
|
||||
using Unity.Jobs;
|
||||
using UnityEngine;
|
||||
using UnityEngine.Networking;
|
||||
using UnityEngine.UI;
|
||||
|
||||
|
||||
@@ -192,15 +193,20 @@ public class SandboxMain : MonoBehaviour
|
||||
async UniTask RunJobAsync()
|
||||
{
|
||||
var job = new MyJob() { loopCount = 999, inOut = new NativeArray<int>(1, Allocator.TempJob) };
|
||||
JobHandle.ScheduleBatchedJobs();
|
||||
try
|
||||
{
|
||||
JobHandle.ScheduleBatchedJobs();
|
||||
|
||||
var scheduled = job.Schedule();
|
||||
var scheduled = job.Schedule();
|
||||
|
||||
UnityEngine.Debug.Log("OK");
|
||||
await scheduled; // .ConfigureAwait(PlayerLoopTiming.Update); // .WaitAsync(PlayerLoopTiming.Update);
|
||||
UnityEngine.Debug.Log("OK2");
|
||||
|
||||
job.inOut.Dispose();
|
||||
UnityEngine.Debug.Log("OK");
|
||||
await scheduled; // .ConfigureAwait(PlayerLoopTiming.Update); // .WaitAsync(PlayerLoopTiming.Update);
|
||||
UnityEngine.Debug.Log("OK2");
|
||||
}
|
||||
finally
|
||||
{
|
||||
job.inOut.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -243,8 +249,49 @@ public class SandboxMain : MonoBehaviour
|
||||
public int MyProperty { get; set; }
|
||||
}
|
||||
|
||||
async Task Test1()
|
||||
{
|
||||
var r = await TcsAsync("https://bing.com/");
|
||||
Debug.Log("TASKASYNC");
|
||||
}
|
||||
|
||||
void Start()
|
||||
async UniTaskVoid Test2()
|
||||
{
|
||||
try
|
||||
{
|
||||
var cts = new CancellationTokenSource();
|
||||
var r = UniAsync("https://bing.com/", cts.Token);
|
||||
cts.Cancel();
|
||||
await r;
|
||||
Debug.Log("UNIASYNC");
|
||||
}
|
||||
catch
|
||||
{
|
||||
Debug.Log("Canceled");
|
||||
}
|
||||
}
|
||||
|
||||
IEnumerator Test3(string url)
|
||||
{
|
||||
var req = UnityWebRequest.Get(url).SendWebRequest();
|
||||
yield return req;
|
||||
Debug.Log("COROUTINE");
|
||||
}
|
||||
|
||||
static async Task<UnityWebRequest> TcsAsync(string url)
|
||||
{
|
||||
var req = await UnityWebRequest.Get(url).SendWebRequest();
|
||||
return req;
|
||||
}
|
||||
|
||||
static async UniTask<UnityWebRequest> UniAsync(string url, CancellationToken cancellationToken)
|
||||
{
|
||||
var req = await UnityWebRequest.Get(url).SendWebRequest().WithCancellation(cancellationToken);
|
||||
return req;
|
||||
}
|
||||
|
||||
|
||||
void Start()
|
||||
{
|
||||
//UniTaskAsyncEnumerable.EveryValueChanged(mcc, x => x.MyProperty)
|
||||
// .Do(_ => { }, () => Debug.Log("COMPLETED"))
|
||||
@@ -254,6 +301,9 @@ public class SandboxMain : MonoBehaviour
|
||||
// })
|
||||
// .Forget();
|
||||
|
||||
_ = Test1();
|
||||
Test2().Forget();
|
||||
StartCoroutine(Test3("https://bing.com/"));
|
||||
|
||||
|
||||
// DG.Tweening.Core.TweenerCore<int>
|
||||
|
||||
Reference in New Issue
Block a user