优化对象池查找速度
This commit is contained in:
parent
9da67afe50
commit
d5518c46b1
@ -221,6 +221,16 @@ namespace AlicizaX
|
|||||||
return m_LinkedList.Contains(value);
|
return m_LinkedList.Contains(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 确定指定结点是否在链表中。
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="node">要检查的结点。</param>
|
||||||
|
/// <returns>指定结点是否在链表中。</returns>
|
||||||
|
public bool Contains(LinkedListNode<T> node)
|
||||||
|
{
|
||||||
|
return node != null && node.List == m_LinkedList;
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 从目标数组的指定索引处开始将整个链表复制到兼容的一维数组。
|
/// 从目标数组的指定索引处开始将整个链表复制到兼容的一维数组。
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|||||||
@ -101,18 +101,19 @@ namespace AlicizaX
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="key">指定的主键。</param>
|
/// <param name="key">指定的主键。</param>
|
||||||
/// <param name="value">指定的值。</param>
|
/// <param name="value">指定的值。</param>
|
||||||
public void Add(TKey key, TValue value)
|
public LinkedListNode<TValue> Add(TKey key, TValue value)
|
||||||
{
|
{
|
||||||
GameFrameworkLinkedListRange<TValue> range = default(GameFrameworkLinkedListRange<TValue>);
|
GameFrameworkLinkedListRange<TValue> range = default(GameFrameworkLinkedListRange<TValue>);
|
||||||
if (m_Dictionary.TryGetValue(key, out range))
|
if (m_Dictionary.TryGetValue(key, out range))
|
||||||
{
|
{
|
||||||
m_LinkedList.AddBefore(range.Terminal, value);
|
return m_LinkedList.AddBefore(range.Terminal, value);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
LinkedListNode<TValue> first = m_LinkedList.AddLast(value);
|
LinkedListNode<TValue> first = m_LinkedList.AddLast(value);
|
||||||
LinkedListNode<TValue> terminal = m_LinkedList.AddLast(default(TValue));
|
LinkedListNode<TValue> terminal = m_LinkedList.AddLast(default(TValue));
|
||||||
m_Dictionary.Add(key, new GameFrameworkLinkedListRange<TValue>(first, terminal));
|
m_Dictionary.Add(key, new GameFrameworkLinkedListRange<TValue>(first, terminal));
|
||||||
|
return first;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -131,9 +132,41 @@ namespace AlicizaX
|
|||||||
{
|
{
|
||||||
if (current.Value.Equals(value))
|
if (current.Value.Equals(value))
|
||||||
{
|
{
|
||||||
if (current == range.First)
|
return Remove(key, current);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 从指定的主键中移除指定结点。
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="key">指定的主键。</param>
|
||||||
|
/// <param name="node">要移除的结点。</param>
|
||||||
|
/// <returns>是否移除成功。</returns>
|
||||||
|
public bool Remove(TKey key, LinkedListNode<TValue> node)
|
||||||
{
|
{
|
||||||
LinkedListNode<TValue> next = current.Next;
|
if (node == null)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
GameFrameworkLinkedListRange<TValue> range = default(GameFrameworkLinkedListRange<TValue>);
|
||||||
|
if (!m_Dictionary.TryGetValue(key, out range))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!m_LinkedList.Contains(node) || node == range.Terminal)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (node == range.First)
|
||||||
|
{
|
||||||
|
LinkedListNode<TValue> next = node.Next;
|
||||||
if (next == range.Terminal)
|
if (next == range.Terminal)
|
||||||
{
|
{
|
||||||
m_LinkedList.Remove(next);
|
m_LinkedList.Remove(next);
|
||||||
@ -145,14 +178,9 @@ namespace AlicizaX
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
m_LinkedList.Remove(current);
|
m_LinkedList.Remove(node);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 从指定的主键中移除所有的值。
|
/// 从指定的主键中移除所有的值。
|
||||||
|
|||||||
@ -1,4 +1,5 @@
|
|||||||
using System;
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
using AlicizaX;
|
using AlicizaX;
|
||||||
|
|
||||||
namespace AlicizaX.ObjectPool
|
namespace AlicizaX.ObjectPool
|
||||||
@ -11,16 +12,20 @@ namespace AlicizaX.ObjectPool
|
|||||||
/// <typeparam name="T">对象类型。</typeparam>
|
/// <typeparam name="T">对象类型。</typeparam>
|
||||||
private sealed class Object<T> : IMemory where T : ObjectBase
|
private sealed class Object<T> : IMemory where T : ObjectBase
|
||||||
{
|
{
|
||||||
|
private string m_Name;
|
||||||
private T m_Object;
|
private T m_Object;
|
||||||
private int m_SpawnCount;
|
private int m_SpawnCount;
|
||||||
|
private LinkedListNode<Object<T>> m_NameNode;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 初始化内部对象的新实例。
|
/// 初始化内部对象的新实例。
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public Object()
|
public Object()
|
||||||
{
|
{
|
||||||
|
m_Name = null;
|
||||||
m_Object = null;
|
m_Object = null;
|
||||||
m_SpawnCount = 0;
|
m_SpawnCount = 0;
|
||||||
|
m_NameNode = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -28,7 +33,7 @@ namespace AlicizaX.ObjectPool
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public string Name
|
public string Name
|
||||||
{
|
{
|
||||||
get { return m_Object.Name; }
|
get { return m_Name; }
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -81,6 +86,15 @@ namespace AlicizaX.ObjectPool
|
|||||||
get { return m_SpawnCount; }
|
get { return m_SpawnCount; }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 获取或设置对象在名字桶中的链表结点。
|
||||||
|
/// </summary>
|
||||||
|
public LinkedListNode<Object<T>> NameNode
|
||||||
|
{
|
||||||
|
get { return m_NameNode; }
|
||||||
|
internal set { m_NameNode = value; }
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 创建内部对象。
|
/// 创建内部对象。
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -95,6 +109,7 @@ namespace AlicizaX.ObjectPool
|
|||||||
}
|
}
|
||||||
|
|
||||||
Object<T> internalObject = MemoryPool.Acquire<Object<T>>();
|
Object<T> internalObject = MemoryPool.Acquire<Object<T>>();
|
||||||
|
internalObject.m_Name = obj.Name;
|
||||||
internalObject.m_Object = obj;
|
internalObject.m_Object = obj;
|
||||||
internalObject.m_SpawnCount = spawned ? 1 : 0;
|
internalObject.m_SpawnCount = spawned ? 1 : 0;
|
||||||
if (spawned)
|
if (spawned)
|
||||||
@ -110,8 +125,10 @@ namespace AlicizaX.ObjectPool
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public void Clear()
|
public void Clear()
|
||||||
{
|
{
|
||||||
|
m_Name = null;
|
||||||
m_Object = null;
|
m_Object = null;
|
||||||
m_SpawnCount = 0;
|
m_SpawnCount = 0;
|
||||||
|
m_NameNode = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|||||||
@ -15,8 +15,10 @@ namespace AlicizaX.ObjectPool
|
|||||||
private readonly GameFrameworkMultiDictionary<string, Object<T>> m_Objects;
|
private readonly GameFrameworkMultiDictionary<string, Object<T>> m_Objects;
|
||||||
private readonly Dictionary<object, Object<T>> m_ObjectMap;
|
private readonly Dictionary<object, Object<T>> m_ObjectMap;
|
||||||
private readonly ReleaseObjectFilterCallback<T> m_DefaultReleaseObjectFilterCallback;
|
private readonly ReleaseObjectFilterCallback<T> m_DefaultReleaseObjectFilterCallback;
|
||||||
private readonly List<T> m_CachedCanReleaseObjects;
|
private readonly List<Object<T>> m_CachedCanReleaseObjects;
|
||||||
private readonly List<T> m_CachedToReleaseObjects;
|
private readonly List<Object<T>> m_CachedToReleaseObjects;
|
||||||
|
private readonly List<T> m_CachedCanReleaseTargets;
|
||||||
|
private readonly IComparer<Object<T>> m_ReleaseObjectComparer;
|
||||||
private readonly bool m_AllowMultiSpawn;
|
private readonly bool m_AllowMultiSpawn;
|
||||||
private float m_AutoReleaseInterval;
|
private float m_AutoReleaseInterval;
|
||||||
private int m_Capacity;
|
private int m_Capacity;
|
||||||
@ -39,8 +41,10 @@ namespace AlicizaX.ObjectPool
|
|||||||
m_Objects = new GameFrameworkMultiDictionary<string, Object<T>>();
|
m_Objects = new GameFrameworkMultiDictionary<string, Object<T>>();
|
||||||
m_ObjectMap = new Dictionary<object, Object<T>>();
|
m_ObjectMap = new Dictionary<object, Object<T>>();
|
||||||
m_DefaultReleaseObjectFilterCallback = DefaultReleaseObjectFilterCallback;
|
m_DefaultReleaseObjectFilterCallback = DefaultReleaseObjectFilterCallback;
|
||||||
m_CachedCanReleaseObjects = new List<T>();
|
m_CachedCanReleaseObjects = new List<Object<T>>();
|
||||||
m_CachedToReleaseObjects = new List<T>();
|
m_CachedToReleaseObjects = new List<Object<T>>();
|
||||||
|
m_CachedCanReleaseTargets = new List<T>();
|
||||||
|
m_ReleaseObjectComparer = Comparer<Object<T>>.Create(ReleaseObjectComparer);
|
||||||
m_AllowMultiSpawn = allowMultiSpawn;
|
m_AllowMultiSpawn = allowMultiSpawn;
|
||||||
m_AutoReleaseInterval = autoReleaseInterval;
|
m_AutoReleaseInterval = autoReleaseInterval;
|
||||||
Capacity = capacity;
|
Capacity = capacity;
|
||||||
@ -163,7 +167,7 @@ namespace AlicizaX.ObjectPool
|
|||||||
}
|
}
|
||||||
|
|
||||||
Object<T> internalObject = Object<T>.Create(obj, spawned);
|
Object<T> internalObject = Object<T>.Create(obj, spawned);
|
||||||
m_Objects.Add(obj.Name, internalObject);
|
internalObject.NameNode = m_Objects.Add(internalObject.Name, internalObject);
|
||||||
m_ObjectMap.Add(obj.Target, internalObject);
|
m_ObjectMap.Add(obj.Target, internalObject);
|
||||||
|
|
||||||
if (Count > m_Capacity)
|
if (Count > m_Capacity)
|
||||||
@ -393,17 +397,7 @@ namespace AlicizaX.ObjectPool
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (internalObject.IsInUse || internalObject.Locked || !internalObject.CustomCanReleaseFlag)
|
return ReleaseObject(internalObject);
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
m_Objects.Remove(internalObject.Name, internalObject);
|
|
||||||
m_ObjectMap.Remove(internalObject.Peek().Target);
|
|
||||||
|
|
||||||
internalObject.Release(false);
|
|
||||||
MemoryPool.Release(internalObject);
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -444,6 +438,12 @@ namespace AlicizaX.ObjectPool
|
|||||||
throw new GameFrameworkException("Release object filter callback is invalid.");
|
throw new GameFrameworkException("Release object filter callback is invalid.");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (releaseObjectFilterCallback == m_DefaultReleaseObjectFilterCallback)
|
||||||
|
{
|
||||||
|
ReleaseWithDefaultFilter(toReleaseCount);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (toReleaseCount < 0)
|
if (toReleaseCount < 0)
|
||||||
{
|
{
|
||||||
toReleaseCount = 0;
|
toReleaseCount = 0;
|
||||||
@ -457,7 +457,13 @@ namespace AlicizaX.ObjectPool
|
|||||||
|
|
||||||
m_AutoReleaseTime = 0f;
|
m_AutoReleaseTime = 0f;
|
||||||
GetCanReleaseObjects(m_CachedCanReleaseObjects);
|
GetCanReleaseObjects(m_CachedCanReleaseObjects);
|
||||||
List<T> toReleaseObjects = releaseObjectFilterCallback(m_CachedCanReleaseObjects, toReleaseCount, expireTime);
|
m_CachedCanReleaseTargets.Clear();
|
||||||
|
foreach (Object<T> internalObject in m_CachedCanReleaseObjects)
|
||||||
|
{
|
||||||
|
m_CachedCanReleaseTargets.Add(internalObject.Peek());
|
||||||
|
}
|
||||||
|
|
||||||
|
List<T> toReleaseObjects = releaseObjectFilterCallback(m_CachedCanReleaseTargets, toReleaseCount, expireTime);
|
||||||
if (toReleaseObjects == null || toReleaseObjects.Count <= 0)
|
if (toReleaseObjects == null || toReleaseObjects.Count <= 0)
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
@ -476,7 +482,7 @@ namespace AlicizaX.ObjectPool
|
|||||||
{
|
{
|
||||||
m_AutoReleaseTime = 0f;
|
m_AutoReleaseTime = 0f;
|
||||||
GetCanReleaseObjects(m_CachedCanReleaseObjects);
|
GetCanReleaseObjects(m_CachedCanReleaseObjects);
|
||||||
foreach (T toReleaseObject in m_CachedCanReleaseObjects)
|
foreach (Object<T> toReleaseObject in m_CachedCanReleaseObjects)
|
||||||
{
|
{
|
||||||
ReleaseObject(toReleaseObject);
|
ReleaseObject(toReleaseObject);
|
||||||
}
|
}
|
||||||
@ -523,6 +529,7 @@ namespace AlicizaX.ObjectPool
|
|||||||
m_ObjectMap.Clear();
|
m_ObjectMap.Clear();
|
||||||
m_CachedCanReleaseObjects.Clear();
|
m_CachedCanReleaseObjects.Clear();
|
||||||
m_CachedToReleaseObjects.Clear();
|
m_CachedToReleaseObjects.Clear();
|
||||||
|
m_CachedCanReleaseTargets.Clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
private Object<T> GetObject(object target)
|
private Object<T> GetObject(object target)
|
||||||
@ -541,7 +548,95 @@ namespace AlicizaX.ObjectPool
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void GetCanReleaseObjects(List<T> results)
|
private bool ReleaseObject(Object<T> internalObject)
|
||||||
|
{
|
||||||
|
if (internalObject == null)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (internalObject.IsInUse || internalObject.Locked || !internalObject.CustomCanReleaseFlag)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
T targetObject = internalObject.Peek();
|
||||||
|
if (targetObject == null)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!m_Objects.Remove(internalObject.Name, internalObject.NameNode))
|
||||||
|
{
|
||||||
|
m_Objects.Remove(internalObject.Name, internalObject);
|
||||||
|
}
|
||||||
|
|
||||||
|
internalObject.NameNode = null;
|
||||||
|
m_ObjectMap.Remove(targetObject.Target);
|
||||||
|
|
||||||
|
internalObject.Release(false);
|
||||||
|
MemoryPool.Release(internalObject);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ReleaseWithDefaultFilter(int toReleaseCount)
|
||||||
|
{
|
||||||
|
if (toReleaseCount < 0)
|
||||||
|
{
|
||||||
|
toReleaseCount = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
DateTime expireTime = DateTime.MinValue;
|
||||||
|
bool checkExpire = m_ExpireTime < float.MaxValue;
|
||||||
|
if (checkExpire)
|
||||||
|
{
|
||||||
|
expireTime = DateTime.UtcNow.AddSeconds(-m_ExpireTime);
|
||||||
|
}
|
||||||
|
|
||||||
|
m_AutoReleaseTime = 0f;
|
||||||
|
if (Count <= 0 || (toReleaseCount <= 0 && !checkExpire))
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
GetCanReleaseObjects(m_CachedCanReleaseObjects);
|
||||||
|
if (m_CachedCanReleaseObjects.Count <= 0)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
m_CachedToReleaseObjects.Clear();
|
||||||
|
int remainingCount = 0;
|
||||||
|
for (int i = 0; i < m_CachedCanReleaseObjects.Count; i++)
|
||||||
|
{
|
||||||
|
Object<T> candidateObject = m_CachedCanReleaseObjects[i];
|
||||||
|
if (checkExpire && candidateObject.LastUseTime <= expireTime)
|
||||||
|
{
|
||||||
|
m_CachedToReleaseObjects.Add(candidateObject);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
m_CachedCanReleaseObjects[remainingCount++] = candidateObject;
|
||||||
|
}
|
||||||
|
|
||||||
|
int additionalReleaseCount = toReleaseCount - m_CachedToReleaseObjects.Count;
|
||||||
|
if (additionalReleaseCount > 0 && remainingCount > 0)
|
||||||
|
{
|
||||||
|
m_CachedCanReleaseObjects.Sort(0, remainingCount, m_ReleaseObjectComparer);
|
||||||
|
int takeCount = additionalReleaseCount < remainingCount ? additionalReleaseCount : remainingCount;
|
||||||
|
for (int i = 0; i < takeCount; i++)
|
||||||
|
{
|
||||||
|
m_CachedToReleaseObjects.Add(m_CachedCanReleaseObjects[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (Object<T> toReleaseObject in m_CachedToReleaseObjects)
|
||||||
|
{
|
||||||
|
ReleaseObject(toReleaseObject);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void GetCanReleaseObjects(List<Object<T>> results)
|
||||||
{
|
{
|
||||||
if (results == null)
|
if (results == null)
|
||||||
{
|
{
|
||||||
@ -557,13 +652,13 @@ namespace AlicizaX.ObjectPool
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
results.Add(internalObject.Peek());
|
results.Add(internalObject);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private List<T> DefaultReleaseObjectFilterCallback(List<T> candidateObjects, int toReleaseCount, DateTime expireTime)
|
private List<T> DefaultReleaseObjectFilterCallback(List<T> candidateObjects, int toReleaseCount, DateTime expireTime)
|
||||||
{
|
{
|
||||||
m_CachedToReleaseObjects.Clear();
|
m_CachedCanReleaseTargets.Clear();
|
||||||
|
|
||||||
if (expireTime > DateTime.MinValue)
|
if (expireTime > DateTime.MinValue)
|
||||||
{
|
{
|
||||||
@ -571,13 +666,13 @@ namespace AlicizaX.ObjectPool
|
|||||||
{
|
{
|
||||||
if (candidateObjects[i].LastUseTime <= expireTime)
|
if (candidateObjects[i].LastUseTime <= expireTime)
|
||||||
{
|
{
|
||||||
m_CachedToReleaseObjects.Add(candidateObjects[i]);
|
m_CachedCanReleaseTargets.Add(candidateObjects[i]);
|
||||||
candidateObjects.RemoveAt(i);
|
candidateObjects.RemoveAt(i);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
toReleaseCount -= m_CachedToReleaseObjects.Count;
|
toReleaseCount -= m_CachedCanReleaseTargets.Count;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (int i = 0; toReleaseCount > 0 && i < candidateObjects.Count; i++)
|
for (int i = 0; toReleaseCount > 0 && i < candidateObjects.Count; i++)
|
||||||
@ -593,11 +688,22 @@ namespace AlicizaX.ObjectPool
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
m_CachedToReleaseObjects.Add(candidateObjects[i]);
|
m_CachedCanReleaseTargets.Add(candidateObjects[i]);
|
||||||
toReleaseCount--;
|
toReleaseCount--;
|
||||||
}
|
}
|
||||||
|
|
||||||
return m_CachedToReleaseObjects;
|
return m_CachedCanReleaseTargets;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static int ReleaseObjectComparer(Object<T> a, Object<T> b)
|
||||||
|
{
|
||||||
|
int priorityCompare = a.Priority.CompareTo(b.Priority);
|
||||||
|
if (priorityCompare != 0)
|
||||||
|
{
|
||||||
|
return priorityCompare;
|
||||||
|
}
|
||||||
|
|
||||||
|
return a.LastUseTime.CompareTo(b.LastUseTime);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user