Ця стаття є дзеркальною статтею машинного перекладу, будь ласка, натисніть тут, щоб перейти до оригінальної статті.

Вид: 6317|Відповідь: 3

[Джерело] [Поворот]. Оптимізації продуктивності NET — швидкий перегляд колекцій списків

[Копіювати посилання]
Опубліковано 2022-8-28 20:51:16 | | | |
Короткий вступ

System.Collections.Generric.List <T>— це універсальний клас колекцій у .NET, який може зберігати будь-який тип даних завдяки своїй зручності та багатому API, що широко використовується в нашому повсякденному житті і вважається найпоширенішим класом колекцій.

Під час написання коду нам часто доводиться проходити <T>колекцію списків, щоб отримати елементи з неї для певної бізнес-обробки. Зазвичай у наборі не так багато елементів, і його дуже швидко пересувати. Але для обробки великих даних, статистики, обчислень у реальному часі тощо<T>, як швидко пройти список із десятків чи сотень тисяч даних? Ось чим я хочу поділитися з вами сьогодні.

Режим пересування

Давайте розглянемо продуктивність різних методів обходу і побудуємо наступний еталонний орієнтир, використовуючи обхід колекції різних порядків, щоб побачити ефективність різних методів. Фрагмент коду виглядає так:

Використовуйте твердження foreach

Foreach — це найпоширеніший спосіб, яким ми проходимо колекції, це синтаксисна цукрова реалізація ітераторного патерну, а також використовується як еталонна для цього часу.

Оскільки оператор foreach є синтаксичним цукрам, компілятор зрештою викликає GetEnumerator() і MoveNext() з циклом while для реалізації функціональності. Скомпільований код виглядає так:



Реалізація методу MoveNext() гарантує, що в ітерації не буде інших потоків, які змінюють колекцію, і якщо модифікація відбудеться, буде видано виключення InvalidOperationException, буде перевірка переповнення для перевірки легітимності поточного індексу, а також потрібно призначити відповідний елемент переписувачу. Поточний атрибут,Тож насправді його продуктивність не найкраща, фрагмент коду виглядає так:



Давайте подивимось, як він працює при різних розмірах наборів, і результати виглядають так:



Видно, що у випадку різних розмірів потрібна лінійна залежність зростання тривалого процесу, навіть якщо він проходить 100 Вт даних без жодної логіки обробки, це займає щонайменше 1 секунду.

Використовуйте метод ForEach для списку

Ще один поширений спосіб — використовувати List<T>. Метод ForEach(), який дозволяє передавати <T>делегата Дії, який викликає делегата Дії під час проходження елемента<T>.

Це <T>внутрішній метод реалізації List, що дозволяє безпосередньо отримувати доступ до приватних масивів і уникати перевірок переповнення. Теоретично це має бути швидко; Але в нашому сценарії є лише один порожній метод, який може погано працювати при повністю вбудованому виклику методу foreach. Нижче наведено вихідний код методу ForEach, який показує, що він не має перевірки переповнення, але все одно зберігає перевірку номера версії одночасно.



Крім того, оскільки необхідно передати делегата методу ForEach, у коді виклику він перевіряє, чи є об'єкт делегата в класі генерації закриття порожнім щоразу, а якщо ні — новий Action<T>(), як показано нижче:



Давайте подивимось, як це порівнюється з ключовим словом foreach за продуктивністю. Наступне зображення показує результати бенчмарку:



Судячи з результатів тесту, це на 40% повільніше, ніж пряме використання ключового слова foreach, і якщо це не потрібно, краще використовувати безпосередньо foreach, тож чи є якийсь швидший спосіб?

для об'їзду петлі

Повертаючись до нашого найдавнішого способу — використовувати ключове слово «for» для проходження колекції. Це має бути найкращий метод обходу на даний момент, оскільки він не потребує дублюючого коду, як попередні (хоча індексер також перевіряється для запобігання переповненням), і, очевидно, він не перевіряє номер версії, тому в багатопотоковому середовищі колекція змінюється, і при використанні для не буде жодного винятку. Тестовий код виглядає так:

Подивимось, що вийде.



Здається, саме так ми цього очікуємо.Використання прямого циклу For на 60% швидше, ніж Foreach, набір, який раніше проходив за 1 секунду, тепер займає лише 400 мілісекунд. То чи є швидший спосіб?

Використання колекційМаршал

Після .NET5 спільнота dotnet впровадила клас CollectionsMarshal для покращення ефективності операцій збору. Цей клас реалізує, як отримати доступ до рідних масивів типів колекцій (якщо ви бачили мій [. .NET Performance Optimization - You Should Set the Initial Size for Collection Types, ви знаєте, що основна реалізація багатьох структур даних — це масиви). Отже, він може пропускати всі види виявлень і безпосередньо отримувати доступ до оригінального масиву, який має бути найшвидшим. Код виглядає так:

Видно, що код, згенерований компілятором, дуже ефективний.



Прямий доступ до базового масиву дуже небезпечний, потрібно знати, що робити з кожним рядком коду, і мати достатньо тестів. Еталонні результати такі:



Вау,Використання CollectionsMarshal на 79% швидше, ніж foreach, але це має бути причиною оптимізації JIT, немає великої різниці між використанням foreach і для циклу ключових слів Span.

зведення

Сьогодні я говорив з вами про те, як швидко проходити колекцію List, і в більшості випадків рекомендується використовувати ключове слово foreach, яке має як перевірку переповнення, так і багатопотоковий контроль номера версії, що може полегшити написання правильного коду.

Якщо вам потрібні високопродуктивні та великі обсяги даних, рекомендується використовувати для та CollectionsMarshal.AsSpan безпосередньо для проходження колекції.

Посилання на вихідний код цієї статті:

Вхід за гіперпосиланням видно.

Оригінальне посилання:Вхід за гіперпосиланням видно.





Попередній:Детальне пояснення архітектури повідомлень RabbitMQ AMQP
Наступний:Стандарти мережевих кристалічних головок T568A та T568B та різниця
Опубліковано 2022-9-4 22:15:52 |
Вчитися вчитися
Опубліковано 2022-9-8 10:33:05 |
Вчитися вчитися
Опубліковано 2023-6-27 22:39:13 |
Привіт, 12306, чи можете ви надіслати мені приватне повідомлення з даними?
Застереження:
Усе програмне забезпечення, програмні матеріали або статті, опубліковані Code Farmer Network, призначені лише для навчання та досліджень; Вищезазначений контент не повинен використовуватися в комерційних чи незаконних цілях, інакше користувачі несуть усі наслідки. Інформація на цьому сайті надходить з Інтернету, і спори щодо авторських прав не мають до цього сайту. Ви повинні повністю видалити вищезазначений контент зі свого комп'ютера протягом 24 годин після завантаження. Якщо вам подобається програма, будь ласка, підтримуйте справжнє програмне забезпечення, купуйте реєстрацію та отримайте кращі справжні послуги. Якщо є будь-яке порушення, будь ласка, зв'яжіться з нами електронною поштою.

Mail To:help@itsvse.com