Когато изграждате приложения, често срещате обекти, които са доста скъпи за създаване. В някои сценарии разходите за създаване на нови обекти са достатъчно високи, за да повлияят на производителността на приложението. Тук на помощ идва моделът на проектиране на обектния басейн.
Шаблонът за проектиране на обектен пул е творчески модел на дизайн, който се използва за рециклиране на обекти, вместо да ги пресъздава всеки път, когато приложението се нуждае от тях. Като съхранява повторно използваеми екземпляри на обекти в пула ресурси и ги разпределя при необходимост, този модел помага да се сведе до минимум режийните разходи за инициализиране, инстанциране и изхвърляне на обекти и за повишаване на производителността на вашето приложение.
Когато приложението поиска обект и обектът е наличен от пула, той се връща от пула. Ако обектът от искания тип не е наличен от пула, тогава се създава и връща нов екземпляр на обекта. Когато приложението вече не се нуждае от обекта, обектът се изпраща обратно в пула.
Минималният и максималният брой обекти, които обектният пул може да побере, е конфигурируем. Ако приложението се нуждае от обект от пула, но е разпределен максималният брой обекти, типично изпълнение на обект от потребителски пул може да възприеме една или повече от следните стратегии:
- Връща null или изхвърля изключение
- Блокирайте повикването, докато има наличен обект
- Увеличете размера на басейна, за да поберете повече обекти
Обектният пул е подобен на пула за връзка с база данни. Точно както пулът от връзки контролира максималния брой връзки към базата данни, обектният пул контролира броя на екземплярите на класа, които приложението ще използва.
Създаване на общ пул от обекти в C #
След като вече знаем основите, нека да преминем към изпълнението. Когато прилагаме шаблона за проектиране на обектния пул, трябва да вземем предвид повторната употреба, простотата, конфигурируемостта и дори фактори като безопасността на нишките.
В този пример ще се възползваме от ConcurrentBag
клас за съхраняване на обекти. Обърнете внимание, че ConcurrentBag
класът в System.Collections.Concurrent
пространството на имената осигурява без заключване, обезопасена с нишки, неподредена колекция от елементи. Също така имайте предвид, че вмъкването и премахването на обекти от и до ConcurrentBag
е много бързо - особено ако същата нишка се опитва да вмъква и премахва елементи от колекцията едновременно.
Ето структурата на нашия потребителски ObjectPool
клас. Обърнете внимание на използването на ConcurrentBag
екземпляра за съхраняване на обектите.
публичен клас ObjectPool където T: new (){
частни елементи за четене ConcurrentBag = нов ConcurrentBag ();
частен брояч int = 0;
private int MAX = 10;
Публично освобождаване (T артикул)
{
//ДА НАПРАВЯ
}
публично T Вземете ()
{
//ДА НАПРАВЯ
}
}
Следният кодов фрагмент илюстрира изпълнение на Get
метода. В Get
метода се връща екземпляр от обект басейна, ако има такъв. Ако няма наличен, се създава и връща нов обект. И в двата сценария counter
променливата се увеличава или намалява според случая. Имайте предвид, че тъй като използваме едновременна колекция, т.е. ConcurrentBag
в този пример се грижи за едновременността.
публично T Вземете (){
Т артикул;
if (items.TryTake (out item))
{
брояч—;
Върни предмета;
}
друго
{
T obj = ново T ();
items.Add (obj);
брояч ++;
return obj;
}
}
В MAX
променливата число е твърдо кодирана тук, но можете да го направите конфигурируеми. Този клас не е запечатан или статичен, така че можете да го разширите, както искате.
В Release
метода се използва за освобождаване на обекти, които вече не са необходими обратно към обект басейна. Той проверява дали стойността на counter
променливата е по-малка от стойността на MAX
променливата и ако е така, добавя обекта, предаден към нея като параметър към колекцията.
Публично освобождаване (T артикул){
ако (брояч <MAX)
{
items.Add (артикул);
брояч ++;
}
}
Ако приемем, че сте създали клас, наречен MyClass
, ето как можете да го добавите към обектния пул с помощта на ObjectPool
класа.
static void Main (низ [] аргументи){
ObjectPool objPool = нов ObjectPool ();
MyClass obj = objPool.Get ();
objPool.Release (obj);
Console.Read ();
}
Можете да модифицирате тази реализация на персонализиран обект, за да позволите минималните и максималните размери на пула да бъдат прочетени от конфигурационен файл. Като част от инициализацията на обектния пул, можете също така да гарантирате, че пулът съдържа минималния брой обекти в него.
Пуловете на обекти помагат за намаляване на режийните разходи, когато имате нужда от множество екземпляри на клас, които са скъпи за създаване или управление. Ако вашето приложение включва инстанциране на едни и същи класове отново и отново, използвайте този модел на проектиране, за да осигурите оптимална производителност.