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