123 lines
		
	
	
		
			3.2 KiB
		
	
	
	
		
			C#
		
	
	
	
			
		
		
	
	
			123 lines
		
	
	
		
			3.2 KiB
		
	
	
	
		
			C#
		
	
	
	
| 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;
 | |
|         }
 | |
|     }
 | |
| } |