CSharp重写对象池

混江龙づ霸主 提交于 2019-12-04 18:44:28

编者注

由于在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

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!