rename StackNode to TaskPool

pull/61/head
neuecc 2020-05-29 02:08:11 +09:00
parent a8455af16d
commit d5db96b913
6 changed files with 90 additions and 63 deletions

View File

@ -234,7 +234,7 @@ namespace NetCoreSandbox
await c;
foreach (var item in Cysharp.Threading.Tasks.Internal.StackNodeMonitor.GetCacheSizeInfo())
foreach (var item in Cysharp.Threading.Tasks.Internal.TaskPoolMonitor.GetCacheSizeInfo())
{
Console.WriteLine(item);
}

View File

@ -29,9 +29,11 @@ namespace Cysharp.Threading.Tasks.CompilerServices
void SetException(Exception exception);
}
internal sealed class MoveNextRunner<TStateMachine> : IMoveNextRunner, IStackNode<MoveNextRunner<TStateMachine>>
internal sealed class MoveNextRunner<TStateMachine> : IMoveNextRunner, ITaskPoolNode<MoveNextRunner<TStateMachine>>
where TStateMachine : IAsyncStateMachine
{
static TaskPool<MoveNextRunner<TStateMachine>> pool;
TStateMachine stateMachine;
public Action MoveNext { get; }
@ -43,7 +45,7 @@ namespace Cysharp.Threading.Tasks.CompilerServices
public static void SetStateMachine(ref AsyncUniTaskVoidMethodBuilder builder, ref TStateMachine stateMachine)
{
if (!StackNodeHelper.TryPop(ref cacheLock, ref size, ref nodeRoot, out var result))
if (!pool.TryPop(out var result))
{
result = new MoveNextRunner<TStateMachine>();
}
@ -52,13 +54,9 @@ namespace Cysharp.Threading.Tasks.CompilerServices
result.stateMachine = stateMachine; // copy struct StateMachine(in release build).
}
static int cacheLock;
static int size;
static MoveNextRunner<TStateMachine> nodeRoot;
static MoveNextRunner()
{
StackNodeMonitor.RegisterSizeGettter(typeof(MoveNextRunner<TStateMachine>), () => size);
TaskPoolMonitor.RegisterSizeGettter(typeof(MoveNextRunner<TStateMachine>), () => pool.Size);
}
public MoveNextRunner<TStateMachine> NextNode { get; set; }
@ -66,7 +64,7 @@ namespace Cysharp.Threading.Tasks.CompilerServices
public void Return()
{
stateMachine = default;
StackNodeHelper.TryPush(ref cacheLock, ref size, ref nodeRoot, this);
pool.TryPush(this);
}
[DebuggerHidden]
@ -77,9 +75,11 @@ namespace Cysharp.Threading.Tasks.CompilerServices
}
}
internal class MoveNextRunnerPromise<TStateMachine> : IMoveNextRunnerPromise, IUniTaskSource, IStackNode<MoveNextRunnerPromise<TStateMachine>>
internal class MoveNextRunnerPromise<TStateMachine> : IMoveNextRunnerPromise, IUniTaskSource, ITaskPoolNode<MoveNextRunnerPromise<TStateMachine>>
where TStateMachine : IAsyncStateMachine
{
static TaskPool<MoveNextRunnerPromise<TStateMachine>> pool;
TStateMachine stateMachine;
public Action MoveNext { get; }
@ -93,7 +93,7 @@ namespace Cysharp.Threading.Tasks.CompilerServices
public static void SetStateMachine(ref AsyncUniTaskMethodBuilder builder, ref TStateMachine stateMachine)
{
if (!StackNodeHelper.TryPop(ref cacheLock, ref size, ref nodeRoot, out var result))
if (!pool.TryPop(out var result))
{
result = new MoveNextRunnerPromise<TStateMachine>();
}
@ -103,15 +103,11 @@ namespace Cysharp.Threading.Tasks.CompilerServices
result.stateMachine = stateMachine; // copy struct StateMachine(in release build).
}
static int cacheLock;
static int size;
static MoveNextRunnerPromise<TStateMachine> nodeRoot;
public MoveNextRunnerPromise<TStateMachine> NextNode { get; set; }
static MoveNextRunnerPromise()
{
StackNodeMonitor.RegisterSizeGettter(typeof(MoveNextRunnerPromise<TStateMachine>), () => size);
TaskPoolMonitor.RegisterSizeGettter(typeof(MoveNextRunnerPromise<TStateMachine>), () => pool.Size);
}
bool TryReturn()
@ -119,7 +115,7 @@ namespace Cysharp.Threading.Tasks.CompilerServices
TaskTracker.RemoveTracking(this);
core.Reset();
stateMachine = default;
return StackNodeHelper.TryPush(ref cacheLock, ref size, ref nodeRoot, this);
return pool.TryPush(this);
}
[DebuggerHidden]
@ -190,9 +186,11 @@ namespace Cysharp.Threading.Tasks.CompilerServices
}
}
internal class MoveNextRunnerPromise<TStateMachine, T> : IMoveNextRunnerPromise<T>, IUniTaskSource<T>, IStackNode<MoveNextRunnerPromise<TStateMachine, T>>
internal class MoveNextRunnerPromise<TStateMachine, T> : IMoveNextRunnerPromise<T>, IUniTaskSource<T>, ITaskPoolNode<MoveNextRunnerPromise<TStateMachine, T>>
where TStateMachine : IAsyncStateMachine
{
static TaskPool<MoveNextRunnerPromise<TStateMachine, T>> pool;
TStateMachine stateMachine;
public Action MoveNext { get; }
@ -206,7 +204,7 @@ namespace Cysharp.Threading.Tasks.CompilerServices
public static void SetStateMachine(ref AsyncUniTaskMethodBuilder<T> builder, ref TStateMachine stateMachine)
{
if (!StackNodeHelper.TryPop(ref cacheLock, ref size, ref nodeRoot, out var result))
if (!pool.TryPop(out var result))
{
result = new MoveNextRunnerPromise<TStateMachine, T>();
}
@ -216,15 +214,11 @@ namespace Cysharp.Threading.Tasks.CompilerServices
result.stateMachine = stateMachine; // copy struct StateMachine(in release build).
}
static int cacheLock;
static int size;
static MoveNextRunnerPromise<TStateMachine, T> nodeRoot;
public MoveNextRunnerPromise<TStateMachine, T> NextNode { get; set; }
static MoveNextRunnerPromise()
{
StackNodeMonitor.RegisterSizeGettter(typeof(MoveNextRunnerPromise<TStateMachine, T>), () => size);
TaskPoolMonitor.RegisterSizeGettter(typeof(MoveNextRunnerPromise<TStateMachine, T>), () => pool.Size);
}
bool TryReturn()
@ -232,7 +226,7 @@ namespace Cysharp.Threading.Tasks.CompilerServices
TaskTracker.RemoveTracking(this);
core.Reset();
stateMachine = default;
return StackNodeHelper.TryPush(ref cacheLock, ref size, ref nodeRoot, this);
return pool.TryPush(this);
}
[DebuggerHidden]

View File

@ -30,9 +30,34 @@ namespace Cysharp.Threading.Tasks
return new UniTask(EnumeratorPromise.Create(enumerator, timing, cancellationToken, out var token), token);
}
class EnumeratorPromise : IUniTaskSource, IPlayerLoopItem, IPromisePoolItem
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.RegisterSizeGettter(typeof(EnumeratorPromise), () => pool.Size);
}
static EnumeratorPromise Create()
{
if (!pool.TryPop(out var result))
{
result = new EnumeratorPromise();
}
TaskTracker.TrackActiveTask(result, 4);
return result;
}
bool TryReturn()
{
TaskTracker.RemoveTracking(this);
core.Reset();
innerEnumerator = default;
cancellationToken = default;
return pool.TryPush(this);
}
IEnumerator innerEnumerator;
CancellationToken cancellationToken;
@ -50,13 +75,11 @@ namespace Cysharp.Threading.Tasks
return AutoResetUniTaskCompletionSource.CreateFromCanceled(cancellationToken, out token);
}
var result = pool.TryRent() ?? new EnumeratorPromise();
var result = Create();
result.innerEnumerator = ConsumeEnumerator(innerEnumerator);
result.cancellationToken = cancellationToken;
TaskTracker.TrackActiveTask(result, 3);
PlayerLoopHelper.AddAction(timing, result);
token = result.core.Version;
@ -67,12 +90,11 @@ namespace Cysharp.Threading.Tasks
{
try
{
TaskTracker.RemoveTracking(this);
core.GetResult(token);
}
finally
{
pool.TryReturn(this);
TryReturn();
}
}
@ -125,7 +147,7 @@ namespace Cysharp.Threading.Tasks
~EnumeratorPromise()
{
if (pool.TryReturn(this))
if (TryReturn())
{
GC.ReRegisterForFinalize(this);
}

View File

@ -1,18 +1,22 @@
using System;
using System.Collections.Concurrent;
using System.Runtime.CompilerServices;
namespace Cysharp.Threading.Tasks.Internal
{
internal sealed class PooledDelegate<T>
internal sealed class PooledDelegate<T> : ITaskPoolNode<PooledDelegate<T>>
{
static readonly ConcurrentQueue<PooledDelegate<T>> pool = new ConcurrentQueue<PooledDelegate<T>>();
static TaskPool<PooledDelegate<T>> pool;
public PooledDelegate<T> NextNode { get; set; }
static PooledDelegate()
{
TaskPoolMonitor.RegisterSizeGettter(typeof(PooledDelegate<T>), () => pool.Size);
}
readonly Action<T> runDelegate;
Action continuation;
PooledDelegate()
{
runDelegate = Run;
@ -21,7 +25,7 @@ namespace Cysharp.Threading.Tasks.Internal
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Action<T> Create(Action continuation)
{
if (!pool.TryDequeue(out var item))
if (!pool.TryPop(out var item))
{
item = new PooledDelegate<T>();
}
@ -37,9 +41,9 @@ namespace Cysharp.Threading.Tasks.Internal
continuation = null;
if (call != null)
{
pool.Enqueue(this);
pool.TryPush(this);
call.Invoke();
}
}
}
}
}

View File

@ -8,16 +8,11 @@ namespace Cysharp.Threading.Tasks.Internal
{
// internaly used but public, allow to user create custom operator with pooling.
public interface IStackNode<T>
public static class TaskPool
{
T NextNode { get; set; }
}
internal static int MaxPoolSize;
public static class StackNodeHelper
{
static int MaxPoolSize;
static StackNodeHelper()
static TaskPool()
{
try
{
@ -40,15 +35,28 @@ namespace Cysharp.Threading.Tasks.Internal
{
MaxPoolSize = maxPoolSize;
}
}
// Strictness as a Stack is not required.
// If there is a conflict, it will go through as is.
public interface ITaskPoolNode<T>
{
T NextNode { get; set; }
}
// mutable struct, don't mark readonly.
public struct TaskPool<T>
where T : class, ITaskPoolNode<T>
{
int gate;
int size;
T root;
public int Size => size;
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static bool TryPop<T>(ref int stackLock, ref int size, ref T root, out T result)
where T : class, IStackNode<T>
public bool TryPop(out T result)
{
if (Interlocked.CompareExchange(ref stackLock, 1, 0) == 0)
if (Interlocked.CompareExchange(ref gate, 1, 0) == 0)
{
var v = root;
if (!(v is null))
@ -57,40 +65,39 @@ namespace Cysharp.Threading.Tasks.Internal
v.NextNode = null;
size--;
result = v;
Volatile.Write(ref stackLock, 0);
Volatile.Write(ref gate, 0);
return true;
}
Volatile.Write(ref stackLock, 0);
Volatile.Write(ref gate, 0);
}
result = default;
return false;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static bool TryPush<T>(ref int stackLock, ref int size, ref T root, T item)
where T : class, IStackNode<T>
public bool TryPush(T item)
{
if (Interlocked.CompareExchange(ref stackLock, 1, 0) == 0)
if (Interlocked.CompareExchange(ref gate, 1, 0) == 0)
{
if (size < MaxPoolSize)
if (size < TaskPool.MaxPoolSize)
{
item.NextNode = root;
root = item;
size++;
Volatile.Write(ref stackLock, 0);
Volatile.Write(ref gate, 0);
return true;
}
else
{
Volatile.Write(ref stackLock, 0);
Volatile.Write(ref gate, 0);
}
}
return false;
}
}
public static class StackNodeMonitor
public static class TaskPoolMonitor
{
static ConcurrentDictionary<Type, Func<int>> sizes = new ConcurrentDictionary<Type, Func<int>>();