You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
123 lines
3.2 KiB
123 lines
3.2 KiB
using System; |
|
using System.Collections.Concurrent; |
|
using System.Collections.Generic; |
|
using System.Runtime.CompilerServices; |
|
using System.Runtime.InteropServices; |
|
using System.Threading; |
|
|
|
namespace Cysharp.Threading.Tasks |
|
{ |
|
// internally used but public, allow to user create custom operator with pooling. |
|
|
|
public static class TaskPool |
|
{ |
|
internal static int MaxPoolSize; |
|
|
|
// avoid to use ConcurrentDictionary for safety of WebGL build. |
|
static Dictionary<Type, Func<int>> sizes = new Dictionary<Type, Func<int>>(); |
|
|
|
static TaskPool() |
|
{ |
|
try |
|
{ |
|
var value = Environment.GetEnvironmentVariable("UNITASK_MAX_POOLSIZE"); |
|
if (value != null) |
|
{ |
|
if (int.TryParse(value, out var size)) |
|
{ |
|
MaxPoolSize = size; |
|
return; |
|
} |
|
} |
|
} |
|
catch { } |
|
|
|
MaxPoolSize = int.MaxValue; |
|
} |
|
|
|
public static void SetMaxPoolSize(int maxPoolSize) |
|
{ |
|
MaxPoolSize = maxPoolSize; |
|
} |
|
|
|
public static IEnumerable<(Type, int)> GetCacheSizeInfo() |
|
{ |
|
lock (sizes) |
|
{ |
|
foreach (var item in sizes) |
|
{ |
|
yield return (item.Key, item.Value()); |
|
} |
|
} |
|
} |
|
|
|
public static void RegisterSizeGetter(Type type, Func<int> getSize) |
|
{ |
|
lock (sizes) |
|
{ |
|
sizes[type] = getSize; |
|
} |
|
} |
|
} |
|
|
|
public interface ITaskPoolNode<T> |
|
{ |
|
ref T NextNode { get; } |
|
} |
|
|
|
// mutable struct, don't mark readonly. |
|
[StructLayout(LayoutKind.Auto)] |
|
public struct TaskPool<T> |
|
where T : class, ITaskPoolNode<T> |
|
{ |
|
int gate; |
|
int size; |
|
T root; |
|
|
|
public int Size => size; |
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|
public bool TryPop(out T result) |
|
{ |
|
if (Interlocked.CompareExchange(ref gate, 1, 0) == 0) |
|
{ |
|
var v = root; |
|
if (!(v is null)) |
|
{ |
|
ref var nextNode = ref v.NextNode; |
|
root = nextNode; |
|
nextNode = null; |
|
size--; |
|
result = v; |
|
Volatile.Write(ref gate, 0); |
|
return true; |
|
} |
|
|
|
Volatile.Write(ref gate, 0); |
|
} |
|
result = default; |
|
return false; |
|
} |
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|
public bool TryPush(T item) |
|
{ |
|
if (Interlocked.CompareExchange(ref gate, 1, 0) == 0) |
|
{ |
|
if (size < TaskPool.MaxPoolSize) |
|
{ |
|
item.NextNode = root; |
|
root = item; |
|
size++; |
|
Volatile.Write(ref gate, 0); |
|
return true; |
|
} |
|
else |
|
{ |
|
Volatile.Write(ref gate, 0); |
|
} |
|
} |
|
return false; |
|
} |
|
} |
|
} |