我不想写自己的,因为我害怕我可能会遗漏某些东西和/或扯掉其他人的工作,那么.NET库中是否存在一个ObjectPool(或类似的)类?
通过对象池,我的意思是一个帮助缓存需要很长时间才能创建的对象的类,通常用于提高性能。
答案 0 :(得分:16)
在即将发布的.NET(4.0)版本中,有一个ConcurrentBag<T>
类,可以在ObjectPool<T>
实现中轻松使用;事实上,there's an article on MSDN向您展示了如何做到这一点。
如果您无权访问最新的.NET框架,则可以从Microsoft's Reactive Extensions (Rx) library(在System中)获取.NET 3.5中的System.Collections.Concurrent
命名空间(其中包含ConcurrentBag<T>
)。 Threading.dll)。
答案 1 :(得分:12)
更新:
我还提出了来自TPL DataFlow的BufferBlock<T>
。 IIRC它现在是.net的一部分。关于BufferBlock<T>
的好处是,您可以使用Post<T>
和ReceiveAsync<T>
扩展方法异步等待项目变为可用。在异步/等待世界中非常方便。
原始答案
前段时间我遇到了这个问题,并提出了一个轻量级(粗略已经)线程安全(我希望)的池,它已被证明非常有用,可重用且健壮:
public class Pool<T> where T : class
{
private readonly Queue<AsyncResult<T>> asyncQueue = new Queue<AsyncResult<T>>();
private readonly Func<T> createFunction;
private readonly HashSet<T> pool;
private readonly Action<T> resetFunction;
public Pool(Func<T> createFunction, Action<T> resetFunction, int poolCapacity)
{
this.createFunction = createFunction;
this.resetFunction = resetFunction;
pool = new HashSet<T>();
CreatePoolItems(poolCapacity);
}
public Pool(Func<T> createFunction, int poolCapacity) : this(createFunction, null, poolCapacity)
{
}
public int Count
{
get
{
return pool.Count;
}
}
private void CreatePoolItems(int numItems)
{
for (var i = 0; i < numItems; i++)
{
var item = createFunction();
pool.Add(item);
}
}
public void Push(T item)
{
if (item == null)
{
Console.WriteLine("Push-ing null item. ERROR");
throw new ArgumentNullException();
}
if (resetFunction != null)
{
resetFunction(item);
}
lock (asyncQueue)
{
if (asyncQueue.Count > 0)
{
var result = asyncQueue.Dequeue();
result.SetAsCompletedAsync(item);
return;
}
}
lock (pool)
{
pool.Add(item);
}
}
public T Pop()
{
T item;
lock (pool)
{
if (pool.Count == 0)
{
return null;
}
item = pool.First();
pool.Remove(item);
}
return item;
}
public IAsyncResult BeginPop(AsyncCallback callback)
{
var result = new AsyncResult<T>();
result.AsyncCallback = callback;
lock (pool)
{
if (pool.Count == 0)
{
lock (asyncQueue)
{
asyncQueue.Enqueue(result);
return result;
}
}
var poppedItem = pool.First();
pool.Remove(poppedItem);
result.SetAsCompleted(poppedItem);
return result;
}
}
public T EndPop(IAsyncResult asyncResult)
{
var result = (AsyncResult<T>) asyncResult;
return result.EndInvoke();
}
}
为了避免池化对象的任何接口要求,对象的创建和重置都由用户提供的委托执行:即
Pool<MemoryStream> msPool = new Pool<MemoryStream>(() => new MemoryStream(2048), pms => {
pms.Position = 0;
pms.SetLength(0);
}, 500);
如果池为空,则BeginPop / EndPop对提供APM(ish)方法,当一个对象可用时异步检索对象(使用Jeff Richter的优秀AsyncResult<TResult>实现)。
我无法完全记住它为什么会被T:class ...那可能没有。
答案 2 :(得分:4)
答案 3 :(得分:0)
System.Collections.Generic.Dictionary怎么样?
答案 4 :(得分:0)
听起来你需要一个带缓存的工厂模式。
您可以尝试使用.net反射器来查看ThreadPool实现。