Про продуктивності іменованих каналів в многопроцессных додатках

У статті про особливості нової версії Visual Studio одним з головних нововведень (з моєї точки зору) виявилося поділ раніше монолітного процесу середовища розробки (devenv.exe) на компоненти, які будуть працювати в окремих процесах. Це вже зроблено для системи контролю версій (переїзд з libgit на git.exe) і деяких плагінів, а в майбутньому і інші частини VS будуть винесені на підпроцеси. У зв'язку з цим в коментарях виникло питання: «А не сповільнить це роботу, адже обмін даними між процесами вимагає використання IPC (Inter Process Communications

Ні, не забариться. І ось чому.

Швидкість
Для організації спілкування між процесами в Windows існують різні технології: сокети, іменовані канали, поділювана пам'ять, обмін повідомленнями. Оскільки писати повноцінний бенчмарк всього вищевказаного мені не хочеться, давайте швиденько пошукаємо щось схоже на Хабре і знайдемо статтю 6-річної давності, в якій adontz порівнював продуктивність сокетів і іменованих каналів. Результати: сокети — 160 мегабайт в секунду, іменовані канали — 755 мегабайт в секунду. При цьому потрібно робити поправку на залізо 6-річної давності і використану для тестів платфому .NET. Тобто можна сміливо стверджувати, що на сучасному залозі з кодом, наприклад, на З ми отримаємо кілька гігабайт в секунду. При цьому, як подсказывает Вікіпедія, швидкість, наприклад, роботи пам'яті DDR3 становить, в залежності від частоти, від 6400 до 19200 МБ/с — і це адже ідеальних МБ/с у вакуумі, на практиці завжди буде менше.

Висновок 1: швидкість роботи пайпов всього в декілька разів менше максимально можливої швидкості роботи оперативної пам'яті. Не в тисячі разів менше, не на порядки, а всього у кілька разів. Сучасні ОС добре роблять свою роботу.

Обсяги даних
Давайте візьмемо все ті ж 755 МБ/с з абзацу вище, як швидкість роботи іменованих каналів. Багато це чи мало? Ну, якби ви, наприклад, писали додаток, яке отримувало б з іменованого каналу необроблений FullHD-відео з частотою 60 кадрів в секунду і щось з ним робили (кодували або стримили) — то вам би для цього вистачило б 355 МБ/с. Т. е. навіть для такої дуже витратною операції швидкості іменованого каналу вистачило б з запасом у два з гаком раз. Чому ж оперує Visual Studio в спілкуванні зі своїми компонентами? Ну, наприклад, командами для git.exe та даними з його відповіді. Це лічені кілобайти, в дуже рідкісних випадках — мегабайти. Обмін даними з плагінами навряд чи можна точно оцінити (дуже різні бувають плагіни). Але в будь-якому разі, ні для одного плагіна, який я бачив, не потрібні сотні мегабайт в секунду.

Висновок 2: з урахуванням специфіки даних, оброблюваних Visual Studio (текст, код, ресурси, картинки), швидкості роботи іменованих каналів вистачає з багатократним запасом.

Latency
Ну гаразд, скажете ви, швидкість-швидкості, але ж є ще й latency. Кожна операція адже потребує якихось накладних витрат на синхронізацію. Так, зажадає. І про це я нещодавно публікував статті. Люди переоцінюють накладні витрати на блокування і синхронізацію. Біда там не в самих локах (вони займають наносекунди), а в тому, що люди пишуть поганий синхронний код, допускають дедлоки, лайвлоки, гонки і пошкодження поділюваної пам'яті. На щастя, у випадку з іменованими каналами сам API натякає на переваги асинхронного підходу і написати коректно працюючий код не так вже складно.

Висновок 3: поки в асинхронному\багатопотоковому коді немає багів — він працює досить швидко, навіть з блокуваннями.

Практичний приклад
Ну гаразд, скажете ви, вистачить теорії, потрібно практичне доказ! І воно у нас є. Це одне з найпопулярніших в світі десктопних додатків — браузер Google Chrome. Створений спочатку у вигляді декількох взаємодіючих процесів, Chrome відразу показав переваги цього підходу — одна вкладка перестала вішати інші, смерть плагіна не означала більше падіння браузера, навантаження в промальовуванні контенту в одному вікні більше не гарантувала гальм в іншому і т. д. Хром, якщо спрощено, запускає один головний процес, окремі процеси для візуалізації вкладок, взаємодії з GPU, плагінів (насправді там правила трохи хитріше, Хром вміє оптимізувати кількість дочірніх процесів в залежності від різних обставин, але це зараз не дуже важливо).

Почитати про архітектуру Хрому можна у них в документацииале ось вам спрощена картинка:

image

Що ж на цій картинці приховує під лінією з розфарбуванням «зебра» і написом IPC? А ось як-раз іменовані канали і ховаються. Їх можна побачити, наприклад, за допомогою програми Process Hacker (вкладка Handles):


Ну або з допомогою Api Monitor:



Наскільки ж іменовані канали гальмують Chrome? Ви і самі знаєте відповідь на це питання: ні на скільки. Мультипроцессная архітектура прискорює браузер, дозволяючи краще розподіляти навантаження між ядрами, краще контролювати продуктивність процесів, ефективніше використовувати пам'ять. Давайте, наприклад, оцінимо, скільки даних Chrome ганяє через свої іменовані канали при програванні однієї хвилини відео з Youtube. Для цього можна скористатися хорошою утилітою IO Ninja (нормально потік даних по пайпу, до їхнього сорому, не показують ні Wireshark, ні API Monitor, ні утиліти Sysinternals — ганьба!):



Вимір показав, що за 1 хвилину програвання Youtube-відео Chrome передає через іменовані канали 76 МБ даних. При цьому окремих операцій читання\запису сталося 79715 штук. Як бачите, навіть таку серйозну програму, як Chrome, навіть на такому неслабом сайті, як Youtube, іменовані канали ні скільки не збентежили. Так що і у Visual Studio є всі шанси виграти від поділу монолітної IDE на підпроцеси.
Джерело: Хабрахабр

0 коментарів

Тільки зареєстровані та авторизовані користувачі можуть залишати коментарі.