12°

CSharp重写对象池

编者注

由于在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();
    /// &lt;summary&gt;
    /// Return an object to the pool.
    /// &lt;/summary&gt;
    /// &lt;param name="obj"&gt;The object to add to the pool.&lt;/param&gt;
    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() =&gt; _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 &lt; items.Length &amp;&amp; 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

本文由【抢小孩糖吃】发布于开源中国,原文链接:https://my.oschina.net/hava/blog/3136947

全部评论: 0

    我有话说: