За известно време в моята компания използвахме домашна реализация ObjectPool<T>
, която осигурява блокиране на достъпа до нейното съдържание. Това е доста лесно: Queue<T>
, object
за заключване и AutoResetEvent
за сигнал към нишка „заемане“, когато се добави елемент.
Същността на класа всъщност са тези два метода:
public T Borrow() {
lock (_queueLock) {
if (_queue.Count > 0)
return _queue.Dequeue();
}
_objectAvailableEvent.WaitOne();
return Borrow();
}
public void Return(T obj) {
lock (_queueLock) {
_queue.Enqueue(obj);
}
_objectAvailableEvent.Set();
}
Използваме този и няколко други класове за събиране вместо предоставените от System.Collections.Concurrent
, защото използваме .NET 3.5, а не 4.0. Но наскоро открихме, че тъй като използваме реактивни разширения, всъщност < em>направете пространството от имена Concurrent
достъпно за нас (в System.Threading.dll).
Естествено реших, че тъй като BlockingCollection<T>
е един от основните класове в Concurrent
namespace, вероятно ще предложи по-добра производителност от всичко, което аз или моите съотборници написах.
Така че се опитах да напиша нова реализация, която работи много просто:
public T Borrow() {
return _blockingCollection.Take();
}
public void Return(T obj) {
_blockingCollection.Add(obj);
}
За моя изненада, според някои прости тестове (заемане/връщане в пула няколко хиляди пъти от множество нишки), нашата първоначална реализация значително побеждава BlockingCollection<T>
по отношение на производителността. И двете изглежда работят правилно; просто нашата оригинална реализация изглежда много по-бърза.
Въпросът ми:
- Защо би било това? Дали може би защото
BlockingCollection<T>
предлага по-голяма гъвкавост (разбрах, че работи чрез обвиване наIProducerConsumerCollection<T>
), което непременно въвежда допълнителни разходи за производителност? - Това просто погрешно използване на класа
BlockingCollection<T>
ли е? - Ако това е подходящо използване на
BlockingCollection<T>
, просто не използвам ли правилно? Например, подходътTake
/Add
твърде опростен ли е и има ли много по-ефективен начин да получите същата функционалност?
Освен ако някой няма какво да предложи в отговор на този трети въпрос, изглежда, че засега ще се придържаме към нашата първоначална реализация.