mirror of
https://gitee.com/jisol/jisol-game/
synced 2025-09-27 10:46:17 +00:00
提交GAS 打算做一个帧同步的GAS
This commit is contained in:
127
JEX_GAS/Assets/GAS/General/Util/Pool/ArrayPool.cs
Normal file
127
JEX_GAS/Assets/GAS/General/Util/Pool/ArrayPool.cs
Normal file
@@ -0,0 +1,127 @@
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Threading;
|
||||
using UnityEngine;
|
||||
using UnityEngine.Profiling;
|
||||
|
||||
namespace GAS.General
|
||||
{
|
||||
public class ArrayPool<T>
|
||||
{
|
||||
private readonly int _maxCapacity;
|
||||
private readonly ConcurrentDictionary<int, Pool> _items = new();
|
||||
|
||||
public ArrayPool(int maxCapacity = 1024)
|
||||
{
|
||||
if (maxCapacity <= 0)
|
||||
{
|
||||
throw new ArgumentOutOfRangeException(nameof(maxCapacity), "maxCapacity must be greater than 0");
|
||||
}
|
||||
|
||||
_maxCapacity = maxCapacity;
|
||||
}
|
||||
|
||||
public T[] Fetch(int length)
|
||||
{
|
||||
return _items.TryGetValue(length, out var pool) ? pool.Get() : new T[length];
|
||||
}
|
||||
|
||||
public bool Recycle(T[] obj)
|
||||
{
|
||||
if (obj == null)
|
||||
{
|
||||
#if UNITY_EDITOR
|
||||
Debug.LogWarning("ArrayPool<T>.Recycle: obj is null");
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!_items.TryGetValue(obj.Length, out var queue))
|
||||
{
|
||||
Profiler.BeginSample("ArrayPoolEx<T>.CreateInstance");
|
||||
queue = _items[obj.Length] = new Pool(obj.Length, _maxCapacity);
|
||||
Profiler.EndSample();
|
||||
}
|
||||
|
||||
return queue.Return(obj);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private class Pool
|
||||
{
|
||||
private readonly int _arrayLength;
|
||||
private readonly int _maxCapacity;
|
||||
private int _numItems;
|
||||
private readonly ConcurrentQueue<T[]> _items = new();
|
||||
private T[] _fastItem;
|
||||
|
||||
public Pool(int arrayLength, int maxCapacity = 128)
|
||||
{
|
||||
if (_arrayLength < 0)
|
||||
{
|
||||
throw new ArgumentOutOfRangeException(nameof(arrayLength), "arrayLength must be greater than or equal to 0");
|
||||
}
|
||||
|
||||
if (maxCapacity <= 0)
|
||||
{
|
||||
throw new ArgumentOutOfRangeException(nameof(maxCapacity), "maxCapacity must be greater than 0");
|
||||
}
|
||||
|
||||
_arrayLength = arrayLength;
|
||||
_maxCapacity = maxCapacity;
|
||||
}
|
||||
|
||||
public T[] Get()
|
||||
{
|
||||
var item = _fastItem;
|
||||
if (item == null || Interlocked.CompareExchange(ref _fastItem, null, item) != item)
|
||||
{
|
||||
if (_items.TryDequeue(out item))
|
||||
{
|
||||
Interlocked.Decrement(ref _numItems);
|
||||
}
|
||||
else
|
||||
{
|
||||
Profiler.BeginSample("ArrayPool<T>.Pool<TT>.CreateInstance");
|
||||
item = new T[_arrayLength];
|
||||
Profiler.EndSample();
|
||||
}
|
||||
}
|
||||
|
||||
return item;
|
||||
}
|
||||
|
||||
public bool Return(T[] obj)
|
||||
{
|
||||
if (obj == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (obj.Length != _arrayLength)
|
||||
{
|
||||
Debug.LogWarning($"Array length({obj.Length}) not match({_arrayLength})");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (_fastItem != null || Interlocked.CompareExchange(ref _fastItem, obj, null) != null)
|
||||
{
|
||||
if (Interlocked.Increment(ref _numItems) <= _maxCapacity)
|
||||
{
|
||||
_items.Enqueue(obj);
|
||||
return true;
|
||||
}
|
||||
|
||||
Interlocked.Decrement(ref _numItems);
|
||||
#if UNITY_EDITOR
|
||||
Debug.LogWarning($"ArrayPool<{typeof(T).FullName}>.Return: Exceed max capacity({_maxCapacity}), consider increase max capacity.");
|
||||
#endif
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
3
JEX_GAS/Assets/GAS/General/Util/Pool/ArrayPool.cs.meta
Normal file
3
JEX_GAS/Assets/GAS/General/Util/Pool/ArrayPool.cs.meta
Normal file
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: ce03b164d35f457b9ce6ff277db4e735
|
||||
timeCreated: 1723102741
|
140
JEX_GAS/Assets/GAS/General/Util/Pool/ObjectPool.cs
Normal file
140
JEX_GAS/Assets/GAS/General/Util/Pool/ObjectPool.cs
Normal file
@@ -0,0 +1,140 @@
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Threading;
|
||||
using UnityEngine;
|
||||
using UnityEngine.Profiling;
|
||||
|
||||
namespace GAS.General
|
||||
{
|
||||
public interface IPool
|
||||
{
|
||||
bool IsFromPool { get; set; }
|
||||
}
|
||||
|
||||
public class ObjectPool
|
||||
{
|
||||
private static ObjectPool _singleton;
|
||||
public static ObjectPool Instance => _singleton ??= new ObjectPool();
|
||||
|
||||
private readonly ConcurrentDictionary<Type, Pool> _objPool = new();
|
||||
|
||||
private readonly Func<Type, Pool> _addPoolFunc = type => new Pool(type, 1024);
|
||||
|
||||
public T Fetch<T>() where T : class
|
||||
{
|
||||
var type = typeof(T);
|
||||
var obj = Fetch(type);
|
||||
return obj as T;
|
||||
}
|
||||
|
||||
public object Fetch(Type type, bool isFromPool = true)
|
||||
{
|
||||
object obj;
|
||||
|
||||
if (!isFromPool)
|
||||
{
|
||||
Profiler.BeginSample("ObjectPool.CreateInstance");
|
||||
obj = Activator.CreateInstance(type);
|
||||
Profiler.EndSample();
|
||||
}
|
||||
else
|
||||
{
|
||||
var pool = GetPool(type);
|
||||
obj = pool.Get();
|
||||
if (obj is IPool p)
|
||||
{
|
||||
p.IsFromPool = true;
|
||||
}
|
||||
}
|
||||
|
||||
return obj;
|
||||
}
|
||||
|
||||
public void Recycle(object obj)
|
||||
{
|
||||
if (obj is IPool p)
|
||||
{
|
||||
if (!p.IsFromPool)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// 防止多次入池
|
||||
p.IsFromPool = false;
|
||||
}
|
||||
|
||||
var type = obj.GetType();
|
||||
var pool = GetPool(type);
|
||||
pool.Return(obj);
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
private Pool GetPool(Type type)
|
||||
{
|
||||
return _objPool.GetOrAdd(type, _addPoolFunc);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 线程安全的无锁对象池
|
||||
/// </summary>
|
||||
private class Pool
|
||||
{
|
||||
private readonly Type _objectType;
|
||||
private readonly int _maxCapacity;
|
||||
private int _numItems;
|
||||
private readonly ConcurrentQueue<object> _items = new();
|
||||
private object _fastItem;
|
||||
|
||||
public Pool(Type objectType, int maxCapacity)
|
||||
{
|
||||
if (maxCapacity <= 0)
|
||||
{
|
||||
throw new ArgumentOutOfRangeException(nameof(maxCapacity), "maxCapacity must be greater than 0");
|
||||
}
|
||||
|
||||
_objectType = objectType;
|
||||
_maxCapacity = maxCapacity;
|
||||
}
|
||||
|
||||
public object Get()
|
||||
{
|
||||
object item = _fastItem;
|
||||
if (item == null || Interlocked.CompareExchange(ref _fastItem, null, item) != item)
|
||||
{
|
||||
if (_items.TryDequeue(out item))
|
||||
{
|
||||
Interlocked.Decrement(ref _numItems);
|
||||
}
|
||||
else
|
||||
{
|
||||
Profiler.BeginSample("Pool.CreateInstance");
|
||||
item = Activator.CreateInstance(_objectType);
|
||||
Profiler.EndSample();
|
||||
}
|
||||
}
|
||||
|
||||
return item;
|
||||
}
|
||||
|
||||
public bool Return(object obj)
|
||||
{
|
||||
if (_fastItem != null || Interlocked.CompareExchange(ref _fastItem, obj, null) != null)
|
||||
{
|
||||
if (Interlocked.Increment(ref _numItems) <= _maxCapacity)
|
||||
{
|
||||
_items.Enqueue(obj);
|
||||
return true;
|
||||
}
|
||||
|
||||
Interlocked.Decrement(ref _numItems);
|
||||
#if UNITY_EDITOR
|
||||
Debug.LogWarning($"Pool<{_objectType.FullName}>.Return: Exceed max capacity({_maxCapacity}), consider increase max capacity.");
|
||||
#endif
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
3
JEX_GAS/Assets/GAS/General/Util/Pool/ObjectPool.cs.meta
Normal file
3
JEX_GAS/Assets/GAS/General/Util/Pool/ObjectPool.cs.meta
Normal file
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: d258d352f22a4281ab0968530960bee5
|
||||
timeCreated: 1713765955
|
Reference in New Issue
Block a user