Przede wszystkim, zgadzam się z @briantyler: ThreadLocal<T>
lub wątek pola statyczne jest prawdopodobnie to, co chcesz. Powinieneś pójść z tym jako punktem wyjścia i rozważyć inne opcje, jeśli nie spełnia Twoich potrzeb.
Skomplikowana, ale elastyczna alternatywa to pojedyncza pula obiektów. W swojej najprostszej postaci twój typ basen będzie wyglądać następująco:
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);
}
}
Nie wydaje strasznie przydatne, jeśli myślisz o rodzaju T
w warunkach prymitywnych klas lub kodowanym (tj ObjectPool<MyComponent>
), w basenie nie ma wbudowanych żadnych elementów sterujących wątkami. Możesz jednak zastąpić monotonę typu T
dla monady i uzyskać dokładnie to, co chcesz.
Basen inicjalizacji:
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());
}
Zastosowanie:
// 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);
}
Ta metoda jest bardziej skomplikowane niż utrzymanie składnika w ThreadLocal
lub nitki statycznego pola, ale jeśli trzeba coś zrobić fantazyjny jak ograniczenie liczba połączonych instancji, abstrakcja puli może być całkiem przydatna.
EDIT
Podstawowe „stałe ustawiony instancji X” realizacja basen z Get
który blokuje raz na basen został osuszony:
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);
}
}
}
Chcesz wiedzieć więcej na temat tego elementu. 1) Czy jest to komponent COM? 2) W jaki sposób obsługujecie usługę WCF? IIS? Wewnątrz usługi Windows? Aplikacja na konsolę? 3) Co to jest kontrola instancji usługi WCF? Singel? Za połączenie? Na sesję? – MickyD
Oprócz tego, co powiedział @MickyD, nawiązywanie połączenia w celu utworzenia nowej instancji komponentu nie rozwiązuje problemu z bezpieczeństwem wątków (myślę, że to jeszcze pogorszy). – AWinkle
Wygląda na to, że naprawdę potrzebna jest pula obiektów, a nie pula wątków. –