use PooledDelegate to avoid convert Action to Action<AsyncOperation> allocation

pull/61/head
neuecc 2020-05-27 07:37:16 +09:00
parent 35b933730b
commit 10fb8060fa
8 changed files with 130 additions and 53 deletions

View File

@ -59,7 +59,7 @@ namespace Cysharp.Threading.Tasks
#if NETCOREAPP3_1
public sealed class ThreadPoolWorkItem : IThreadPoolWorkItem
sealed class ThreadPoolWorkItem : IThreadPoolWorkItem
{
static readonly ConcurrentQueue<ThreadPoolWorkItem> pool = new ConcurrentQueue<ThreadPoolWorkItem>();

View File

@ -72,7 +72,7 @@ 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;
}
}
@ -249,7 +249,7 @@ 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;
}
}

View File

@ -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,9 +78,8 @@ 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);
}
}
@ -89,6 +89,8 @@ namespace Cysharp.Threading.Tasks
static readonly Action<object> CancellationCallbackDelegate = CancellationCallback;
static readonly TweenCallback EmptyTweenCallback = () => { };
readonly TweenCallback onKillDelegate;
Tween tween;
TweenCancelBehaviour cancelBehaviour;
CancellationToken cancellationToken;
@ -99,7 +101,7 @@ namespace Cysharp.Threading.Tasks
TweenConfiguredSource()
{
onKillDelegate = OnKill;
}
public static IUniTaskSource Create(Tween tween, TweenCancelBehaviour cancelBehaviour, CancellationToken cancellationToken, out short token)
@ -130,8 +132,7 @@ namespace Cysharp.Threading.Tasks
cancellationTokenRegistration = cancellationToken.RegisterWithoutCaptureExecutionContext(CancellationCallbackDelegate, this);
}
// allocate delegate.
tween.OnKill(new TweenCallback(OnKill));
tween.OnKill(onKillDelegate);
}
void OnKill()
@ -234,6 +235,45 @@ namespace Cysharp.Threading.Tasks
}
}
}
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)]
public void Run()
{
var call = continuation;
continuation = null;
if (call != null)
{
pool.Enqueue(this);
call.Invoke();
}
}
}
}
#endif

View File

@ -0,0 +1,45 @@
using System;
using System.Collections.Concurrent;
using System.Runtime.CompilerServices;
namespace Cysharp.Threading.Tasks.Internal
{
internal class PooledDelegate<T>
{
static readonly ConcurrentQueue<PooledDelegate<T>> pool = new ConcurrentQueue<PooledDelegate<T>>();
readonly Action<T> runDelegate;
Action continuation;
PooledDelegate()
{
runDelegate = Run;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Action<T> Create(Action continuation)
{
if (!pool.TryDequeue(out var item))
{
item = new PooledDelegate<T>();
}
item.continuation = continuation;
return item.runDelegate;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void Run(T _)
{
var call = continuation;
continuation = null;
if (call != null)
{
pool.Enqueue(this);
call.Invoke();
}
}
}
}

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 8932579438742fa40b010edd412dbfba
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -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)
// {
// }
// }
}
}

View File

@ -70,7 +70,7 @@ 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;
}
}
@ -242,7 +242,7 @@ 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;
}
}
@ -419,7 +419,7 @@ 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;
}
}
@ -596,7 +596,7 @@ 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;
}
}
@ -774,7 +774,7 @@ 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;
}
}

View File

@ -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();