Тази статия е огледална статия за машинен превод, моля, кликнете тук, за да преминете към оригиналната статия.

Изглед: 6846|Отговор: 2

[Източник] [Завърти]. .NET оптимизация на производителността - Collections.Pooled се препоръчва

[Копирай линк]
Публикувано на 29.05.2022 13:45:22 | | | |
Кратко въведение

Оптимизацията на производителността означава как да се гарантира, че един и същ брой заявки се обработват с по-малко ресурси, които обикновено са процесор или памет, и разбира се, IO контролите на операционната система, мрежовия трафик, използването на диска и др. Но в повечето случаи намаляваме използването на процесор и памет.
Съдържанието, което беше споделено по-рано, има някои ограничения, трудно е да се трансформира директно, днес искам да споделя с вас един прост метод – трябва само да се заменят няколко типа колекции, за да се постигне ефект на подобряване на производителността и намаляване на отпечатъка на паметта.
Днес искам да споделя с вас една класна библиотека, тазиБиблиотеката на класа се нарича Collections.Pooled, Както се вижда от името, това е чрез обединена памет за постигане на целта за намаляване на отпечатъка на паметта и GC, и ще видим директно как е производителността ѝ, а също така ще ви заведем да видите изходния код и защо носи тези подобрения в производителността.

Колекции. Обединени

Връзка към проекта:Входът към хиперлинк е видим.

Библиотеката е базирана на класове в System.Collections.Generic, които са модифицирани, за да се възползват от новите <T>класови библиотеки System.Span и System.Buffers.ArrayPool <T>с цел намаляване на отделянето на памет, подобряване на производителността и по-голяма съвместимост с модерните API.
Collections.Pooled поддържа .NET Standnd 2.0 (.NET Framework 4.6.1+), както и поддръжка за . NET Core 2.1+. Обширен набор от unit тестове и бенчмаркове е портнат от CoreFX.

Общ брой тестове: 27501. Виза: 27501. Провал: 0. Пропуск: 0.
Тестовото излъчване беше успешно.
Време за изпълнение на теста: 9.9019 секунди

Как да използвате

Можете лесно да инсталирате тази библиотека чрез Nuget, версия NuGet.

В библиотеката Collections.Pooled тя реализира обединени версии за типовете колекции, които обикновено използваме, както е показано при сравнението с .NET родните типове.

. .NET nativeКолекции. ОбединениЗабележка
Списък<T>PooledList<T>Класове на генерични колекции
Речник<TKey, TValue>PooledDictionary<TKey, TValue>Клас на общ речник
HashSet<T>PooledSet<T>Общи класове от колекция от хеш
Стека<T>Стека<T>Общи стекове
Опашка<T>PooledQueue<T>Генерична кохорта

Когато използваме, трябва само да добавим съответния . Родната версия .NET с Collections.Pooled версията, както е показано в кода по-долу:

Въпреки това, трябва да отбележим, че типът Pooled реализира интерфейса IDispose, който връща използваната памет в пула чрез метода Dispose(), затова трябва да извикаме неговия метод Dispose() след използване на обекта Pooled колекция. Или можеш да използваш ключовата дума с var директно.

Забележка: Използвайте колекция обекта вътре в Collections.PooledНай-добре е да го освободиш ръчно, но няма значение, ако не го пуснеш, GC в крайна сметка ще го рециклира, но не може да се върне в пула и няма да постигне ефекта на пестене на памет.
Тъй като използва повторно пространство в паметта, когато връща паметното пространство в пула, трябва да обработи елементите в колекцията и предоставя изброяване, наречено ClearMode, дефинирано по следния начин:




По подразбиране можете да използвате стандартната стойност Auto, а ако има специални изисквания за производителност, можете да използвате Never след като знаете рисковете.
За референтни типове и типове стойности, съдържащи референтни типове, трябва да изпразним референтния масив при връщане на паметното пространство в пула; ако не бъде изчистен, GC няма да може да освободи тази част от паметта (защото референцията на елемента винаги е била задържана от пула), ако е чист тип стойност, тя не може да бъде изпразнена; в тази статия описвам разликата в паметта между референтните типове и структурните (value type) масиви, чистите стойностни типове нямат рециклиране на заглавия на обекта и не изискват намеса на GC.


. .NET оптимизация на производителността - Използвайте алтернативни класове на структури:Входът към хиперлинк е видим.

Сравнение на производителността

Не съм правил Benchmark сам, а резултатите от текущите резултати на open source проекти, които директно използвах, бяха 0 за използване на паметта на много проекти, което се дължи на факта, че използваната пулирана памет нямаше допълнително разпределение.

PooledList<T>

Прегледайте елементите от 2048, добавени към набора в Benchmark, . .NET native List <T>изисква 110us (според реалните резултати от бенчмарка, милисекундите на фигурата трябва да са административна грешка) и 263KB памет, докато <T>PooledList изисква само 36us и 0KB памет.




PooledDictionary<TKey, TValue>

Добавете 10_0000 елемента към речника в цикъл в Benchmark, . .NET native Dictionary<TKey, TValue> изисква 11ms и 13MB памет, докато PooledDictionary<TKey, TValue> изисква само 7ms и 0MB памет.




PooledSet<T>

Прегледай колекцията от хеш в Benchmark и добави 10_0000 елемента, . Родният .NET HashSet <T>изисква 5348ms и 2MB, докато <T>PooledSet изисква само 4723ms и 0MB памет.




PooledStack<T>

Преминете през стека в Benchmark, за да добавите 10_0000 елемента. .NET нативният <T>PooledStack изисква 1079ms и 2MB, докато PooledStack <T>изисква само 633ms и 0MB памет.




PooledQueue<T>

Преминете през циклите в Benchmark, за да добавите 10_0000 елемента към опашката, . .NET нативният <T>PooledQueue изисква 681ms и 1MB, докато <T>PooledQueue изисква само 408ms и 0MB памет.




Сцената не се освобождава ръчно

Освен това споменахме по-горе, че типът на обединената колекция трябва да бъде пуснат, но няма значение дали не е пуснат, защото GC ще рециклира.


Резултатите от Benchmark са следните:



Заключението може да се направи от горните резултати от бенчмарка.

Пускането на Pooled колекцията от типове навреме едва задейства GC и отделя памет, като от горната графика се отделя само 56 байта памет.
Дори ако колекцията от типове Pooled не бъде освободена, тъй като отделя памет от пула, тя все пак ще използва повторно паметта по време на операцията за разширяване на ReSize и ще пропусне стъпката за инициализация на паметта за разпределение на GC, която е сравнително бърза.
Най-бавният е да се използва нормалният тип колекция, всяка операция за разширяване на ReSize трябва да се прилага за ново пространство в паметта, а GC също трябва да възстанови предишното пространство в паметта.


Анализ на принципите

Ако сте чели предишната ми публикация в блога, трябва да зададете началния размер на типовете колекции и да анализирате принципа на имплементация на C# речника, можете да знаете, че разработчиците на .NET BCL използват основните структури от данни на тези основни типове колекции като масиви за високопроизводителен случаен достъп, нека вземем <T>List за пример.

Създайте нов масив, който да съхранява добавените елементи.
Ако няма достатъчно място в масива, се задейства операцията за разширяване, за да се поиска двойно по-голям размер на пространството.
Кодът на конструктора е следният, и можете да видите, че това е генеричен масив, създаден директно:


Така че, ако искате да обедините памет, трябва само да промените мястото, където се използва новото приложение за ключова дума в библиотеката на класовете, за да използвате пулирано приложение. Тук го споделям с теб. NET BCL е тип, наречен ArrayPool, който предоставя масивен ресурсен пул от многократно използваеми генерични инстанции, които могат да се използват за намаляване на натиска върху GC и подобряване на производителността при често създаване и унищожаване на масиви.

Основният слой на нашия тип Pooled е да използваме ArrayPool за споделяне на ресурсни пулове, и от неговия конструктор виждаме, че по подразбиране използва ArrayPool<T>. Споделено за задаване на масивни обекти, и разбира се, можеш да създадеш собствен ArrayPool, за да го използваш.


Освен това, при извършване на операция за корекция на капацитета (разширение), старият масив се връща в пула от нишки, а новият масив също се получава от пула.

Освен това авторът използва Span, за да оптимизира API като Add и Insert, за да им осигури по-добра производителност при произволен достъп. Освен това е добавен TryXXX серия API, така че можете да го използвате по-удобно. Например, <T>класът List <T>има до 170 модификации в сравнение с PooledList.



резюме

В нашата реална онлайн употреба можем да заменим нативния тип колекция с този тип колекция, предоставен от Pooled, което е много полезно за намаляване на използването на памет и латентността на P95.
Също така, дори и да забравиш да го пуснеш, производителността няма да е много по-лоша от използването на нативния тип колекция. Разбира се, най-добрият навик е да го пуснеш навреме.


Оригинален:Входът към хиперлинк е видим.




Предишен:RecyclableMemoryStream предоставя високопроизводителен .NET стрийминг
Следващ:[Практически бой] Сървърът изгражда LibreSpeed, за да тества скоростта на мрежата
Публикувано на 2022-5-29 17:12:36 |
Научи го
Публикувано на 20.06.2022 09:09:22 |
Научете микса
Отричане:
Целият софтуер, програмни материали или статии, публикувани от Code Farmer Network, са само за учебни и изследователски цели; Горното съдържание не трябва да се използва за търговски или незаконни цели, в противен случай потребителите ще понесат всички последствия. Информацията на този сайт идва от интернет, а споровете за авторски права нямат нищо общо с този сайт. Трябва напълно да изтриете горното съдържание от компютъра си в рамките на 24 часа след изтеглянето. Ако ви харесва програмата, моля, подкрепете оригинален софтуер, купете регистрация и получете по-добри услуги. Ако има нарушение, моля, свържете се с нас по имейл.

Mail To:help@itsvse.com