JIT проти статичного компілятора
Як уже було сказано в попередніх публікаціях, JIT може компілювати IL / байт-код у нативний код під час виконання. Вартість цього була згадана, але не до її завершення:
У JIT є одна велика проблема: він не може зібрати все: компіляція JIT потребує часу, тому JIT збирає лише деякі частини коду, тоді як статичний компілятор виробляє повний натурний двійковий код: Для деяких програм статичний компілятор просто легко перевершить JIT.
Звичайно, C # (або Java, або VB) зазвичай швидше виробляють життєздатне і надійне рішення, ніж це C ++ (хоча б тому, що C ++ має складну семантику, а стандартна бібліотека C ++, хоча і цікава і потужна, досить бідна порівняно з повною сфера стандартної бібліотеки від .NET або Java), тому зазвичай різниця між C ++ і .NET або Java JIT не буде видимою для більшості користувачів, а для тих бінарних файлів, які є критичними, добре, ви все одно можете викликати обробку C ++ від C # або Java (навіть якщо цей вид натільних дзвінків сам по собі може бути досить дорогим) ...
C ++ метапрограмування
Зауважте, що зазвичай ви порівнюєте код виконання C ++ з його еквівалентом у C # або Java. Але у C ++ є одна особливість, яка може перевершити Java / C # поза полем, це метапрограмування шаблонів: Обробка коду буде виконана під час компіляції (таким чином, значно збільшується час компіляції), що призводить до нульового (або майже нульового) часу виконання.
Я поки що так не бачу ефекту реального життя на цьому (я грав лише з концепціями, але до цього часу різниця була секундами виконання для JIT, а нуль для C ++), але це варто зазначити, поряд із фактом метапрограмування шаблону немає банальний ...
Редагувати 2011-06-10: У C ++ гра з типами проводиться під час компіляції, тобто виробляється загальний код, який викликає негенеричний код (наприклад, загальний аналізатор від рядка до типу T, викликаючи стандартний API бібліотеки для типів T, який він розпізнає, і зробити парсер легко розширюваним його користувачем) дуже легко і дуже ефективно, тоді як еквівалент в Java або C # в кращому випадку болісний для написання, і завжди буде повільнішим і вирішується під час виконання, навіть коли типи відомі під час компіляції, Це означає, що ваша єдина надія полягає в тому, щоб СІТ все це розкрив.
...
Редагувати 2011-09-20: Команда Blitz ++ ( Домашня сторінка , Вікіпедія ) пішла цим шляхом, і, мабуть, їх мета - досягти ефективності FORTRAN на наукових розрахунках, максимально перемістившись від виконання програми до часу компіляції за допомогою метапрограмування шаблонів C ++. . Тож « я ще не бачив, як реально впливає на це життя », про яку я писав вище, мабуть , існує в реальному житті.
Нативне використання пам'яті C ++
C ++ має використання пам'яті, відмінну від Java / C #, і, таким чином, має різні переваги / недоліки.
Незалежно від оптимізації JIT, нічого не пройде швидко, як прямий доступ до пам’яті (давайте на хвилину ігноруємо кеші процесора тощо). Отже, якщо у вас є суміжні дані в пам'яті, доступ до них за допомогою покажчиків C ++ (тобто, покажчиків C ... Давайте надамо цезарю належне) піде в рази швидше, ніж у Java / C #. І у C ++ є RAII, що робить обробку набагато простішою, ніж у C # або навіть на Java. C ++ не потребує using
обсягу існування своїх об'єктів. А у C ++ немає finally
застереження. Це не помилка.
:-)
І незважаючи на C # примітивні структури, об'єкти C ++ "на стеці" нічого не коштуватимуть при розподілі та знищенні, і GC не потребуватиме роботи в незалежній потоці для очищення.
Що стосується фрагментації пам’яті, то розподільники пам’яті 2008 року - це не старі алокатори пам’яті 1980 року, які зазвичай порівнюються з розподілом GC: C ++ не можна переміщувати в пам’яті, правда, але тоді, як у файловій системі Linux: Кому потрібен жорсткий диск дефрагментація, коли фрагментації не відбувається? Використання правильного алокатора для правильного завдання повинно бути частиною набору інструментів для розробників C ++. Зараз написати алокатори непросто, і тоді, у більшості з нас є кращі справи, і для більшої частини використання RAII або GC - це більш ніж добре.
Редагувати 2011-10-04: Для прикладів щодо ефективних розподільників. На платформах Windows, починаючи з Vista, Heap Fragmentation Heap увімкнено за замовчуванням. Для попередніх версій LFH можна активувати, викликавши функцію WinAPI HeapSetInformation ). На інших ОС передбачені альтернативні розподільники (дивhttps://secure.wikimedia.org/wikipedia/en/wiki/Malloc для списку)
Тепер модель пам'яті дещо ускладнюється із зростанням багатоядерної та багатопотокової технологій. Я думаю, що в цьому полі перевагу .NET має перевагу, і Java, як мені сказали, тримала верхню позицію. Деяким хакерам "на голий метал" легко похвалити його код "біля машини". Але зараз скласти кращу збірку вручну набагато складніше, ніж дозволити компілятору свою роботу. Для C ++ компілятор ставав, як правило, кращим, ніж хакер, починаючи з десятиліття. Для C # та Java це ще простіше.
І все-таки новий стандарт C ++ 0x накладе просту модель пам’яті компіляторам C ++, яка стандартизує (і тим самим спростить) ефективний багатопроцесорний / паралельний / нарізаючий код у C ++ та зробить оптимізацію простішою та безпечнішою для компіляторів. Але потім, ми побачимо через кілька років, чи виконують його обіцянки.
C ++ / CLI проти C # / VB.NET
Примітка. У цьому розділі я говорю про C ++ / CLI, тобто C ++, розміщений у .NET, а не на рідному C ++.
Минулого тижня я пройшов тренінг з оптимізації .NET і виявив, що статичний компілятор дуже важливий у будь-якому випадку. Як важливіше, ніж JIT.
Сам же код, складений в C ++ / CLI (або його предка, керований C ++), може бути в рази швидшим, ніж той самий код, що створюється в C # (або VB.NET, компілятор якого виробляє той же IL, що і C #).
Оскільки статичний компілятор C ++ був набагато кращим для створення вже оптимізованого коду, ніж для C #.
Наприклад, функція, вбудована в .NET, обмежується функціями, байт-код яких менше або дорівнює 32 байтам. Отже, деякий код у C # створить 40-байтний аксесуар, який JIT ніколи не накреслить. Цей же код у C ++ / CLI створить 20-байтний аксесуар, який буде накреслений JIT.
Інший приклад - тимчасові змінні, які просто компілюються компілятором C ++, при цьому все ще згадуються в IL, що виробляється компілятором C #. Статична оптимізація компіляції C ++ призведе до меншої кількості коду, що дозволить знову агресивніше оптимізувати JIT.
Причиною цього вважалося, що компілятор C ++ / CLI отримав прибуток від величезних методів оптимізації від власного компілятора C ++.
Висновок
Я люблю C ++.
Але наскільки я це бачу, C # або Java - в цілому краще. Не тому, що вони швидші за C ++, а тому, що, коли ви додаєте їхні якості, вони в кінцевому підсумку стають більш продуктивними, потребують меншої кількості тренувань та мають більш повні стандартні бібліотеки, ніж C ++. А що стосується більшості програм, то їх різниця в швидкості (так чи інакше) буде незначною ...
Редагувати (06.06.2011)
Мій досвід роботи на C # /. NET
Зараз у мене вже 5 місяців майже ексклюзивного професійного кодування C # (що додає до мого резюме вже повне C ++ та Java, а також C ++ / CLI).
Я грав з WinForms (Ahem ...) і WCF (круто!), І WPF (Cool !!!! Як через XAML, так і з сирої C #. WPF - це так просто, я вважаю, що Swing просто не може з цим порівнятись) і C # 4.0.
Висновок полягає в тому, що хоча простіше / швидше створити код, який працює в C # / Java, ніж у C ++, набагато складніше створити міцний, безпечний і надійний код у C # (і навіть складніше в Java), ніж у C ++. Причин багато, але їх можна підсумувати:
- Загальна версія не настільки потужна, як шаблони ( спробуйте написати ефективний загальний метод Parse (від рядка до T) або ефективний еквівалент boost :: lexical_cast в C #, щоб зрозуміти проблему )
- RAII залишається незрівнянним ( GC все ще може просочитися (так, мені довелося впоратися з цією проблемою) і буде працювати з пам'яттю. Навіть C #
using
не так просто і потужно, тому що писати правильні реалізації Dispose складно )
- C #
readonly
і Java final
ніде не є такими корисними, як C ++const
( Немає можливості викрити лише складні дані (наприклад, Дерево вузлів) у C # без величезної роботи, хоча це вбудована функція C ++. Невідмінні дані - цікаве рішення , але не все можна зробити непорушним, так що, навіть далеко, далеко ).
Отже, C # залишається приємною мовою до тих пір, поки ви хочете, щоб щось працювало, але засмучує мову в той момент, коли ви хочете щось, що завжди і безпечно працює.
Java ще більше засмучує, оскільки у неї є ті самі проблеми, що і у C #, і багато іншого: Не вистачаючи еквівалента using
ключового слова C # , мій дуже кваліфікований колега витратив занадто багато часу, переконуючись, що його ресурси звільнені правильно, тоді як еквівалент C ++ мав би було легко (за допомогою деструкторів та розумних покажчиків).
Тому я здогадуюсь, що підвищення продуктивності C # / Java видно для більшості кодів ... до дня, коли вам потрібен код, щоб бути максимально досконалим. Того дня ви будете знати біль. (Ви не повірите, що запитують від нашого сервера та GUI-додатків ...).
Про сервер Java та C ++
Я підтримував зв’язок із серверними командами (я працював 2 роки серед них, перш ніж повернутися до команди GUI), з іншого боку будівлі, і дізнався щось цікаве.
Останніми роками тенденція полягала в тому, щоб додатки для сервера Java були призначені замінити старі серверні програми C ++, оскільки Java має багато рамок / інструментів, і їх легко обслуговувати, розгортати тощо тощо.
... Доки проблема з низькою затримкою не виросла свою потворну голову в останні місяці. Тоді програми Java-сервера, незалежно від того, яку оптимізацію намагалася наша кваліфікована команда Java, просто та чисто програли гонку проти старого, не дуже оптимізованого сервера C ++.
В даний час рішення полягає в тому, щоб зберегти сервери Java для загального використання там, де продуктивність, хоча це все ще важливо, не стосується цілі з низькою затримкою, і агресивно оптимізувати вже швидші серверні програми C ++ для потреб із низькою затримкою та наднизькою затримкою.
Висновок
Ніщо не є таким простим, як очікувалося.
Java і навіть більше C # - це круті мови, з великими стандартними бібліотеками та фреймворками, де ви можете швидко вводити коди та мати результат дуже скоро.
Але коли вам потрібна сильна потужність, потужна та систематизована оптимізація, сильна підтримка компілятора, потужні мовні функції та абсолютна безпека, Java та C # ускладнюють перемогу останнього пропущеного, але критичного відсотка якості, який потрібно залишатись вище конкуренції.
Це як би вам потрібно менше часу та менш досвідчені розробники на C # / Java, ніж у C ++, щоб створити код середньої якості, але, з іншого боку, у той момент, коли вам знадобився відмінний для вдосконалення коду якості, раптом було простіше та швидше отримати результати прямо в C ++.
Звичайно, це моє власне сприйняття, можливо, обмежене нашими конкретними потребами.
Але все-таки це відбувається сьогодні, як в командах GUI, так і в командах на сервері.
Звичайно, я оновлю цю посаду, якщо трапиться щось нове.
Редагувати (2011-06-22)
"Ми виявляємо, що щодо продуктивності C ++ виграє з великим відривом. Однак, це також вимагало найширших налаштувань зусиль, багато з яких були зроблені на рівні складності, яка не була б доступною середньому програмісту.
[...] Версія Java, мабуть, була найпростішою у здійсненні, але найскладнішою для аналізу продуктивності. Зокрема, ефекти навколо вивезення сміття були складними і дуже важко налаштовані ".
Джерела:
Редагувати (2011-09-20)
"Слово у Facebook полягає в тому, що" розумно написаний код C ++ просто працює швидко ", що підкреслює величезні зусилля, витрачені на оптимізацію PHP та Java-коду. Як не парадоксально, C ++ код важче написати, ніж на інших мовах, але ефективний код - це набагато простіше [писати на C ++, ніж іншими мовами]. "
- Herb Sutter у // build / , цитуючи Андрія Олександреску
Джерела: