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

master
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 #if NETCOREAPP3_1
public sealed class ThreadPoolWorkItem : IThreadPoolWorkItem sealed class ThreadPoolWorkItem : IThreadPoolWorkItem
{ {
static readonly ConcurrentQueue<ThreadPoolWorkItem> pool = new ConcurrentQueue<ThreadPoolWorkItem>(); static readonly ConcurrentQueue<ThreadPoolWorkItem> pool = new ConcurrentQueue<ThreadPoolWorkItem>();

View File

@ -72,7 +72,7 @@ namespace Cysharp.Threading.Tasks
public void UnsafeOnCompleted(Action continuation) public void UnsafeOnCompleted(Action continuation)
{ {
Error.ThrowWhenContinuationIsAlreadyRegistered(continuationAction); Error.ThrowWhenContinuationIsAlreadyRegistered(continuationAction);
continuationAction = continuation.AsFuncOfT<AsyncOperationHandle>(); // allocate delegate. continuationAction = PooledDelegate<AsyncOperationHandle>.Create(continuation);
handle.Completed += continuationAction; handle.Completed += continuationAction;
} }
} }
@ -249,7 +249,7 @@ namespace Cysharp.Threading.Tasks
public void UnsafeOnCompleted(Action continuation) public void UnsafeOnCompleted(Action continuation)
{ {
Error.ThrowWhenContinuationIsAlreadyRegistered(continuationAction); Error.ThrowWhenContinuationIsAlreadyRegistered(continuationAction);
continuationAction = continuation.AsFuncOfT<AsyncOperationHandle>(); // allocate delegate. continuationAction = PooledDelegate<AsyncOperationHandle>.Create(continuation);
handle.CompletedTypeless += continuationAction; handle.CompletedTypeless += continuationAction;
} }
} }

View File

@ -5,6 +5,7 @@
using Cysharp.Threading.Tasks.Internal; using Cysharp.Threading.Tasks.Internal;
using DG.Tweening; using DG.Tweening;
using System; using System;
using System.Collections.Concurrent;
using System.Runtime.CompilerServices; using System.Runtime.CompilerServices;
using System.Threading; using System.Threading;
@ -77,9 +78,8 @@ namespace Cysharp.Threading.Tasks
public void UnsafeOnCompleted(System.Action continuation) public void UnsafeOnCompleted(System.Action continuation)
{ {
// convert Action -> TweenCallback allocation.
// onKill is called after OnCompleted, both Complete(false/true) and Kill(false/true). // 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 Action<object> CancellationCallbackDelegate = CancellationCallback;
static readonly TweenCallback EmptyTweenCallback = () => { }; static readonly TweenCallback EmptyTweenCallback = () => { };
readonly TweenCallback onKillDelegate;
Tween tween; Tween tween;
TweenCancelBehaviour cancelBehaviour; TweenCancelBehaviour cancelBehaviour;
CancellationToken cancellationToken; CancellationToken cancellationToken;
@ -99,7 +101,7 @@ namespace Cysharp.Threading.Tasks
TweenConfiguredSource() TweenConfiguredSource()
{ {
onKillDelegate = OnKill;
} }
public static IUniTaskSource Create(Tween tween, TweenCancelBehaviour cancelBehaviour, CancellationToken cancellationToken, out short token) 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); cancellationTokenRegistration = cancellationToken.RegisterWithoutCaptureExecutionContext(CancellationCallbackDelegate, this);
} }
// allocate delegate. tween.OnKill(onKillDelegate);
tween.OnKill(new TweenCallback(OnKill));
} }
void OnKill() 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 #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() 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) public void UnsafeOnCompleted(Action continuation)
{ {
Error.ThrowWhenContinuationIsAlreadyRegistered(continuationAction); Error.ThrowWhenContinuationIsAlreadyRegistered(continuationAction);
continuationAction = continuation.AsFuncOfT<AsyncOperation>(); // allocate delegate. continuationAction = PooledDelegate<AsyncOperation>.Create(continuation);
asyncOperation.completed += continuationAction; asyncOperation.completed += continuationAction;
} }
} }
@ -242,7 +242,7 @@ namespace Cysharp.Threading.Tasks
public void UnsafeOnCompleted(Action continuation) public void UnsafeOnCompleted(Action continuation)
{ {
Error.ThrowWhenContinuationIsAlreadyRegistered(continuationAction); Error.ThrowWhenContinuationIsAlreadyRegistered(continuationAction);
continuationAction = continuation.AsFuncOfT<AsyncOperation>(); // allocate delegate. continuationAction = PooledDelegate<AsyncOperation>.Create(continuation);
asyncOperation.completed += continuationAction; asyncOperation.completed += continuationAction;
} }
} }
@ -419,7 +419,7 @@ namespace Cysharp.Threading.Tasks
public void UnsafeOnCompleted(Action continuation) public void UnsafeOnCompleted(Action continuation)
{ {
Error.ThrowWhenContinuationIsAlreadyRegistered(continuationAction); Error.ThrowWhenContinuationIsAlreadyRegistered(continuationAction);
continuationAction = continuation.AsFuncOfT<AsyncOperation>(); // allocate delegate. continuationAction = PooledDelegate<AsyncOperation>.Create(continuation);
asyncOperation.completed += continuationAction; asyncOperation.completed += continuationAction;
} }
} }
@ -596,7 +596,7 @@ namespace Cysharp.Threading.Tasks
public void UnsafeOnCompleted(Action continuation) public void UnsafeOnCompleted(Action continuation)
{ {
Error.ThrowWhenContinuationIsAlreadyRegistered(continuationAction); Error.ThrowWhenContinuationIsAlreadyRegistered(continuationAction);
continuationAction = continuation.AsFuncOfT<AsyncOperation>(); // allocate delegate. continuationAction = PooledDelegate<AsyncOperation>.Create(continuation);
asyncOperation.completed += continuationAction; asyncOperation.completed += continuationAction;
} }
} }
@ -774,7 +774,7 @@ namespace Cysharp.Threading.Tasks
public void UnsafeOnCompleted(Action continuation) public void UnsafeOnCompleted(Action continuation)
{ {
Error.ThrowWhenContinuationIsAlreadyRegistered(continuationAction); Error.ThrowWhenContinuationIsAlreadyRegistered(continuationAction);
continuationAction = continuation.AsFuncOfT<AsyncOperation>(); // allocate delegate. continuationAction = PooledDelegate<AsyncOperation>.Create(continuation);
asyncOperation.completed += continuationAction; asyncOperation.completed += continuationAction;
} }
} }

View File

@ -13,7 +13,6 @@ using UnityEngine;
using UnityEngine.Networking; using UnityEngine.Networking;
using UnityEngine.UI; using UnityEngine.UI;
// using DG.Tweening; // using DG.Tweening;
public struct MyJob : IJob public struct MyJob : IJob
@ -259,11 +258,15 @@ public class SandboxMain : MonoBehaviour
{ {
try try
{ {
var cts = new CancellationTokenSource(); //var cts = new CancellationTokenSource();
var r = UniAsync("https://bing.com/", cts.Token); //var r = UniAsync("https://bing.com/", cts.Token);
cts.Cancel(); //cts.Cancel();
await r; //await r;
Debug.Log("UNIASYNC"); _ = await UnityWebRequest.Get("https://bing.com/").SendWebRequest();
Debug.Log("UNIASYNC1 ");
_ = await UnityWebRequest.Get("https://bing.com/").SendWebRequest();
Debug.Log("UNIASYNC2");
} }
catch catch
{ {
@ -291,7 +294,7 @@ public class SandboxMain : MonoBehaviour
} }
void Start() async UniTaskVoid Start()
{ {
//UniTaskAsyncEnumerable.EveryValueChanged(mcc, x => x.MyProperty) //UniTaskAsyncEnumerable.EveryValueChanged(mcc, x => x.MyProperty)
// .Do(_ => { }, () => Debug.Log("COMPLETED")) // .Do(_ => { }, () => Debug.Log("COMPLETED"))
@ -301,15 +304,23 @@ public class SandboxMain : MonoBehaviour
// }) // })
// .Forget(); // .Forget();
_ = Test1(); //_ = Test1();
Test2().Forget(); Test2().Forget();
StartCoroutine(Test3("https://bing.com/")); //StartCoroutine(Test3("https://bing.com/"));
// DG.Tweening.Core.TweenerCore<int> // 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( // DOTween.To(
var cts = new CancellationTokenSource(); var cts = new CancellationTokenSource();