C# 객체 풀 ObjectPool의 구현
마찬가지로 대상지는 미리 만들어진 수많은 동일한 대상에서 대상을 찾거나 돌려주기 위해 대상을 중복 이용함으로써 빈번하게 폐기 대상을 만드는 비용을 절약하기 위한 것이다.
대상 탱크는 다중 스레드 조작에 많이 사용되기 때문에 대상 탱크는 일반적으로 스레드가 안전하고 높은 성능을 요구한다.
Microsoft에서 소스를 시작한 Roslyn 컴파일러에서 구현된 ObjectPool(디버그 코드 일부가 삭제됨)을 발췌합니다.
using System;
using System.Diagnostics;
using System.Threading;
namespace Microsoft.CodeAnalysis.PooledObjects
{
///
/// Generic implementation of object pooling pattern with predefined pool size limit. The main purpose is that
/// limited number of frequently used objects can be kept in the pool for further recycling.
///
/// Notes:
/// 1) it is not the goal to keep all returned objects. Pool is not meant for storage. If there is no space in the
/// pool, extra returned objects will be dropped.
///
/// 2) it is implied that if object was obtained from a pool, the caller will return it back in a relatively short
/// time. Keeping checked out objects for long durations is ok, but reduces usefulness of pooling. Just new up your own.
///
/// Not returning objects to the pool in not detrimental to the pool's work, but is a bad practice. Rationale: If
/// there is no intent for reusing the object, do not use pool - just use "new".
///
public class ObjectPool where T : class
{
[DebuggerDisplay("{Value,nq}")]
private struct Element
{
internal T Value;
}
// Not using System.Func{T} because .NET2.0 does not have that type.
public delegate T Factory();
// Storage for the pool objects. The first item is stored in a dedicated field because we expect to be able to
// satisfy most requests from it.
private T _firstItem;
private readonly Element[] _items;
// factory is stored for the lifetime of the pool. We will call this only when pool needs to expand. compared to
// "new T()", Func gives more flexibility to implementers and faster than "new T()".
private readonly Factory _factory;
public ObjectPool(Factory factory)
: this(factory, Environment.ProcessorCount * 2)
{ }
public ObjectPool(Factory factory, int size)
{
Debug.Assert(size >= 1);
_factory = factory;
_items = new Element[size - 1];
}
private T CreateInstance()
{
T inst = _factory();
return inst;
}
///
/// Produces an instance.
///
///
/// Search strategy is a simple linear probing which is chosen for it cache-friendliness. Note that Free will try
/// to store recycled objects close to the start thus statistically reducing how far we will typically search.
///
public T Allocate()
{
// PERF: Examine the first element. If that fails, AllocateSlow will look at the remaining elements. Note
// that the initial read is optimistically not synchronized. That is intentional. We will interlock only when
// we have a candidate. in a worst case we may miss some recently returned objects. Not a big deal.
T inst = _firstItem;
if (inst == null || inst != Interlocked.CompareExchange(ref _firstItem, null, inst))
{
inst = AllocateSlow();
}
return inst;
}
private T AllocateSlow()
{
Element[] items = _items;
for (int i = 0; i < items.Length; i++)
{
// Note that the initial read is optimistically not synchronized. That is intentional. We will interlock
// only when we have a candidate. in a worst case we may miss some recently returned objects. Not a big deal.
T inst = items[i].Value;
if (inst != null)
{
if (inst == Interlocked.CompareExchange(ref items[i].Value, null, inst))
{
return inst;
}
}
}
return CreateInstance();
}
///
/// Returns objects to the pool.
///
///
/// Search strategy is a simple linear probing which is chosen for it cache-friendliness. Note that Free will try
/// to store recycled objects close to the start thus statistically reducing how far we will typically search in Allocate.
///
public void Free(T obj)
{
Validate(obj);
if (_firstItem == null)
{
// Intentionally not using interlocked here. In a worst case scenario two objects may be stored into same
// slot. It is very unlikely to happen and will only mean that one of the objects will get collected.
_firstItem = obj;
}
else
{
FreeSlow(obj);
}
}
private void FreeSlow(T obj)
{
Element[] items = _items;
for (int i = 0; i < items.Length; i++)
{
if (items[i].Value == null)
{
// Intentionally not using interlocked here. In a worst case scenario two objects may be stored into
// same slot. It is very unlikely to happen and will only mean that one of the objects will get collected.
items[i].Value = obj;
break;
}
}
}
[Conditional("DEBUG")]
private void Validate(object obj)
{
Debug.Assert(obj != null, "freeing null?");
Debug.Assert(_firstItem != obj, "freeing twice?");
var items = _items;
for (int i = 0; i < items.Length; i++)
{
var value = items[i].Value;
if (value == null)
{
return;
}
Debug.Assert(value != obj, "freeing twice?");
}
}
}
}
http://source.roslyn.codeplex.com/#Microsoft.CodeAnalysis/ObjectPool%25601.cs
, 。
private struct Element
{
internal T Value;
}
private readonly Element[] _items;
, , List
https://www.red-gate.com/simple-talk/dotnet/.net-framework/5-tips-and-techniques-for-avoiding-automatic-gc-collections/
: ,GC , 。
, , GC 。
GC 。
,Roslyn , , ObjectPool.
:
https://stackoverflow.com/questions/30618067/why-are-there-so-many-implementations-of-object-pooling-in-roslyn
이 내용에 흥미가 있습니까?
현재 기사가 여러분의 문제를 해결하지 못하는 경우 AI 엔진은 머신러닝 분석(스마트 모델이 방금 만들어져 부정확한 경우가 있을 수 있음)을 통해 가장 유사한 기사를 추천합니다:
XXX 플랫폼 전체 아키텍처 설계 어플리케이션 배포미디어 기구 플랫폼 소프트웨어 목록 이름 버전 서버 JDK 1.8.0_육십 transaction-server/trade-server/transaction-app/memberapp/designapp-WebAPI/des...
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
CC BY-SA 2.5, CC BY-SA 3.0 및 CC BY-SA 4.0에 따라 라이센스가 부여됩니다.