编者注
由于在Unity当中,需要申请大量的struct和object。这两个东西在CSharp当中并不统一。导致申请的东西很多,CSharp的GC调用,会导致Unity发生Stop world现象。这个将会让Unity帧速率降低,从而影响用户体验。需要自己找或者写对象池。编者了解Java,更倾向从Java当中抄一部分作为接口与实现。
需求
.Net Standard 2.0标准API实现线程安全的struct及object的池。
调研
Unity 原生
通过Google并没有查找到Unity原生的对象池,看来Unity的原生对象,官方并不提供管理。
Standard 2.0
先到附录3尝试获取信息,发现.Net core
具有所需要的ArrayPool,但是在.Net Standard 2.0
搜索并未发现该内容。
Microsoft简单对象池
通过附录4,微软通过ConcurrentBag创建的一个简单的对象池。虽然微软写的是Object但是,通过ConcurrentBag源代码查看到范型T并未规定为class,能够作为实施备选。并且ConcurrentBag解决了多线程访问。
ASPNet/Extensions/ObjectPool
.NET Extensions能够看到很多的类库。其中就有编者所关注的ObjectPool。通过载入Rider,了解到ObjectPool是支持.Net Standard 2.0标准,确认能够使用。然后确认ObjectPool是否支持struct和多线程安全。
public abstract class ObjectPool<T> where T : class
{
/// <summary>
/// Gets an object from the pool if one is available, otherwise creates one.
/// </summary>
/// <returns>A <typeparamref name="T"/>.</returns>
public abstract T Get();
/// <summary>
/// Return an object to the pool.
/// </summary>
/// <param name="obj">The object to add to the pool.</param>
public abstract void Return(T obj);
}
通过接口了解到ObjectPool被限制在了class当中,无法使用struct。
public override T Get()
{
var item = _firstItem;
if (item == null || Interlocked.CompareExchange(ref _firstItem, null, item) != item)
{
var items = _items;
for (var i = 0; i < items.Length; i++)
{
item = items[i].Element;
if (item != null && Interlocked.CompareExchange(ref items[i].Element, null, item) == item)
{
return item;
}
}
item = Create();
}
return item;
}
// Non-inline to improve its code quality as uncommon path
[MethodImpl(MethodImplOptions.NoInlining)]
private T Create() => _fastPolicy?.Create() ?? _policy.Create();
public override void Return(T obj)
{
if (_isDefaultPolicy || (_fastPolicy?.Return(obj) ?? _policy.Return(obj)))
{
if (_firstItem != null || Interlocked.CompareExchange(ref _firstItem, obj, null) != null)
{
var items = _items;
for (var i = 0; i < items.Length && Interlocked.CompareExchange(ref items[i].Element, obj, null) != null; ++i)
{
}
}
}
}
在DefaultObjectPool的实现,我们能够看到Interlocked的使用。虽然没有测试,但是算做线程安全。
结论:CSharp以及Unity官方并没有太好的解决方案。需要自行实现ObjectPool。
附录
Object Pool & Object Pooling System
Unity3D Object Pooling – Advanced
C# Object Pooling Pattern implementation
How to: Create an Object Pool by Using a ConcurrentBag
Pooling large arrays with ArrayPool
来源:oschina
链接:https://my.oschina.net/hava/blog/3136947