首先,我同意@briantyler:ThreadLocal<T> 或线程静态字段可能是您想要的。您应该以此为起点,如果它不能满足您的需求,请考虑其他选择。
一个复杂但灵活的替代方案是单例对象池。在最简单的形式中,您的池类型将如下所示:
public sealed class ObjectPool<T>
{
private readonly ConcurrentQueue<T> __objects = new ConcurrentQueue<T>();
private readonly Func<T> __factory;
public ObjectPool(Func<T> factory)
{
__factory = factory;
}
public T Get()
{
T obj;
return __objects.TryDequeue(out obj) ? obj : __factory();
}
public void Return(T obj)
{
__objects.Enqueue(obj);
}
}
如果您在原始类或结构(即ObjectPool<MyComponent>)方面考虑类型T,这似乎不是非常有用,因为池没有内置任何线程控件。但您可以替换你的类型 T 为 Lazy<T> 或 Task<T> monad,得到你想要的。
池初始化:
Func<Task<MyComponent>> factory = () => Task.Run(() => new MyComponent());
ObjectPool<Task<MyComponent>> pool = new ObjectPool<Task<MyComponent>>(factory);
// "Pre-warm up" the pool with 16 concurrent tasks.
// This starts the tasks on the thread pool and
// returns immediately without blocking.
for (int i = 0; i < 16; i++) {
pool.Return(pool.Get());
}
用法:
// Get a pooled task or create a new one. The task may
// have already completed, in which case Result will
// be available immediately. If the task is still
// in flight, accessing its Result will block.
Task<MyComponent> task = pool.Get();
try
{
MyComponent component = task.Result; // Alternatively you can "await task"
// Do something with component.
}
finally
{
pool.Return(task);
}
这种方法比在ThreadLocal 或线程静态字段中维护您的组件更复杂,但如果您需要做一些花哨的事情,例如限制池实例的数量,池抽象会非常有用。
编辑
带有Get 的基本“固定X 实例集”池实现,一旦池耗尽就会阻塞:
public sealed class ObjectPool<T>
{
private readonly Queue<T> __objects;
public ObjectPool(IEnumerable<T> items)
{
__objects = new Queue<T>(items);
}
public T Get()
{
lock (__objects)
{
while (__objects.Count == 0) {
Monitor.Wait(__objects);
}
return __objects.Dequeue();
}
}
public void Return(T obj)
{
lock (__objects)
{
__objects.Enqueue(obj);
Monitor.Pulse(__objects);
}
}
}