Для отримання максимальної продуктивності з одночасно виконаними одиницями, напишіть власний пул потоків, де пул об’єктів нитки створюється при запуску і переходить до блокування (раніше призупинено), очікуючи запуску контексту (об'єкт зі стандартним інтерфейсом, реалізований ваш код).
Так багато статей про Tasks vs. Threads vs. .NET ThreadPool насправді не дають тобі, що потрібно для прийняття рішення про ефективність. Але коли їх порівнювати, нитки виграють і особливо пул ниток. Вони розподіляються найкраще по процесорам, і вони запускаються швидше.
Що слід обговорити, це той факт, що головним блоком виконання Windows (включаючи Windows 10) є потік, а контекстна комутація накладних режимів ОС зазвичай незначна. Простіше кажучи, я не зміг знайти переконливі докази багатьох цих статей, чи вимагає ця стаття більш високу ефективність завдяки збереженню переключення контексту або кращому використанню процесора.
Тепер трохи реалізму:
Більшості з нас не потрібно, щоб наш додаток був детермінованим, і більшість з нас не має жорсткого тла з нитками, що, наприклад, часто відбувається при розробці операційної системи. Те, що я писав вище, не для початківців.
Тож, що може бути найважливішим, - це обговорити, що легко запрограмувати.
Якщо ви створюєте власний пул потоків, вам доведеться трохи написати, оскільки вам потрібно буде займатися відстеженням стану виконання, як імітувати призупинення та відновлення та скасування виконання - в тому числі в додатку закрити. Можливо, вам також доведеться перейматися тим, чи хочете ви динамічно розростати свій пул, а також обмеженням потужності вашого пулу. Я можу написати таку рамку за годину, але це тому, що я робив це стільки разів.
Мабуть, найпростіший спосіб написання одиниці виконання - це використання Завдання. Краса Завдання полягає в тому, що ви можете створити її і відкинути її в рядку у своєму коді (хоча може бути обережним). Ви можете передати маркер скасування для обробки, коли ви хочете скасувати завдання. Крім того, він використовує підхід, який обіцяє прив'язувати події, і ви можете мати можливість повернути йому певний тип значення. Більше того, з асинхронізацією та очікуванням існує більше варіантів, і ваш код стане більш портативним.
По суті, важливо зрозуміти плюси і мінуси Завдання проти ниток проти .NET ThreadPool. Якщо мені потрібна висока продуктивність, я збираюся використовувати теми, і я вважаю за краще використовувати власний пул.
Простий спосіб порівняння - це запуск 512 ниток, 512 завдань та 512 ниток потоку пулу. Ви знайдете затримку на початку з Threads (отже, чому писати пул потоків), але всі 512 теми будуть запущені за кілька секунд, тоді як Tasks і .NET ThreadPool запускають до декількох хвилин, щоб усі почалися.
Нижче наводяться результати такого тесту (чотириядерний i5 з 16 ГБ оперативної пам’яті), що дає кожні 30 секунд для запуску. Виконаний код виконує прості введення / виведення файлів на SSD-накопичувачі.
Результати тесту