С # справді повільніший, ніж скажімо C ++?


78

Я вже давно задаюся цим питанням.

Звичайно, у C # є речі, які не оптимізовані для швидкості, тому використання цих об'єктів або налаштування мови (наприклад, LinQ) може спричинити повільніший код.

Але якщо ви не використовуєте жодного з цих налаштувань, а просто порівняєте однакові фрагменти коду в C # та C ++ (легко перекласти один на інший). Чи справді це буде набагато повільніше?

Я бачив порівняння, які показують, що в деяких випадках C # може бути навіть швидшим, оскільки теоретично компілятор JIT повинен оптимізувати код в режимі реального часу та отримувати кращі результати:

Керований чи некерований?

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

GC також не додає багато накладних витрат, якщо ви не створюєте та не знищуєте тисячі об'єктів (наприклад, використовуючи String замість StringBuilder). І робити це в C ++ також буде дорого.

Ще один момент, на який я хочу звернути увагу, - це кращий зв’язок між бібліотеками DLL, введеними в .Net. Платформа .Net спілкується набагато краще, ніж керовані бібліотеки DLL на основі COM.

Я не бачу жодної невід'ємної причини, чому мова повинна бути повільнішою, і я насправді не вважаю, що C # повільніший за C ++ (як з досвіду, так і через відсутність належного пояснення).

Отже, чи буде шматок того самого коду, написаний на C #, повільнішим за той самий код на C ++?
Якщо так, то ЧОМУ?

Деякі інші посилання (які говорять про це трохи, але без пояснення ЧОМУ):

Чому ви хочете використовувати C #, якщо він повільніший за C ++?


Оскільки C # набагато простіший у використанні, ніж C ++, особливо коли йдеться про графічний інтерфейс
Армен Цирунян,

3
Дійсно ... Це залежить ... Деякі речі швидші, інші повільніші. C / C ++ є більш "детермінованим" (немає збирача сміття за спиною). Якщо ви хочете породити 100 потоків, я можу сказати вам, що GC переслідуватиме вас своєю повільністю (і перш ніж говорити мені, що 100 потоків занадто багато, знайте, що Skype і McAfee AV зараз на моєму ПК мають по 40 потоків). .. Маршалінг в C # - це біль (і це повільніше). Кодування відбувається досить швидко. Ні, це не полум'я. Я справді віддаю перевагу C #.
xanatos

1
Думаю, це слід відредагувати та відкрити. Я думаю, що запитувач може не розуміти, що більш фундаментальне питання впливає на різницю в продуктивності між C # та такими мовами, як C або C ++, що означало б "Яка різниця між кодом, який генерується (і як він виконується) компілятором C, та кодом, генерованим Компілятор C #? " C # / Java та інші інтерпретовані мови або мови VM можуть мати кілька посередницьких етапів під час запуску їх байт-коду, які повністю відсутні в еквівалентній програмі на C.
Джонатан Фауст,

3
Хоча ви можете стверджувати, що (як зазначено) це кваліфікується як "не реальне питання", стверджуючи, що воно суб'єктивне, є безглуздим. "Чи швидше, ніж В" - це те, що відкрито для об'єктивного вимірювання. Навіть якщо відповідь, отримана таким виміром, неоднозначна (деякі речі швидші в одному, інші в іншому), він все одно є об’єктивним.
Джеррі Коффін,

1
Подивіться гру для тестування комп’ютерних мов, щоб детально порівняти багато мов із різними типами проблем.
Assaf Lavie

Відповіді:


144

Попередження: Питання, яке ви задали, насправді досить складне - можливо, набагато більше, ніж ви собі уявляєте. Як результат - це дійсно довга відповідь.

З чисто теоретичної точки зору на це є, мабуть, проста відповідь: у C # немає (мабуть) нічого, що справді заважає йому бути таким швидким, як C ++. Однак, незважаючи на теорію, є деякі практичні причини того, що за певних обставин у деяких випадках це відбувається повільніше.

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

Мовні особливості

C ++ робить великий акцент на шаблонах та функціях в системі шаблонів, які в основному призначені для того, щоб якомога більше робити під час компіляції, тому з точки зору програми вони "статичні". Метапрограмування шаблону дозволяє проводити абсолютно довільні обчислення під час компіляції (тобто система шаблонів є повною за Тьюрінгом). Таким чином, по суті все, що не залежить від вводу від користувача, може бути обчислене під час компіляції, тому під час виконання це просто константа. Вхідні дані до цього можуть включати такі речі, як інформація про тип, тому велика частина того, що ви робите за допомогою відображення під час виконання в C #, зазвичай робиться під час компіляції за допомогою метапрограмування шаблону в C ++. Безумовно, існує компроміс між швидкістю виконання та універсальністю - що можуть зробити шаблони,

Відмінності в особливостях мови означають, що майже будь-яка спроба порівняння двох мов шляхом простої транслітерації деякої мови C # на C ++ (або навпаки), ймовірно, дасть результати десь між безглуздими та оманливими (і те саме стосується більшості інших пар мов також). Простий факт полягає в тому, що для будь-чого, що перевищує пару рядків коду або близько того, майже ніхто взагалі не може використовувати мови однаково (або досить близько до того самого шляху), що таке порівняння говорить вам щось про те, як ці мови робота в реальному житті.

Віртуальна машина

Як і майже будь-яка досить сучасна віртуальна машина, Microsoft для .NET може і буде робити компіляцію JIT (вона ж "динамічна"). Це представляє низку компромісів.

В першу чергу, оптимізація коду (як і більшість інших задач оптимізації) є в основному проблемою, що повна NP. Для будь-чого, крім справді тривіальної / іграшкової програми, ви майже гарантовані, що не будете по-справжньому "оптимізувати" результат (тобто ви не знайдете справжнього оптимуму) - оптимізатор просто зробить код кращим за нього було раніше. Проте досить багато відомих оптимізацій займають значну кількість часу (і, часто, пам’яті). За допомогою компілятора JIT користувач чекає, поки компілятор працює. Більшість більш дорогих методів оптимізації виключаються. Статична компіляція має дві переваги: ​​перш за все, якщо вона повільна (наприклад, побудова великої системи), вона зазвичай виконується на сервері і ніхтовитрачає час на його очікування. По-друге, виконуваний файл може бути створений один раз і використаний багатьма людьми багатьма людьми. Перший мінімізує витрати на оптимізацію; другий амортизує набагато меншу вартість за значно більшу кількість страт.

Як згадувалося в оригінальному питанні (та багатьох інших веб-сайтах), компіляція JIT має можливість більш глибокої обізнаності про цільове середовище, що повинно (принаймні теоретично) компенсувати цю перевагу. Немає сумнівів, що цей фактор може компенсувати хоча б частину недоліків статичної компіляції. Для декількох досить специфічних типів коду та цільових середовищ це моженавіть переважують переваги статичної компіляції, іноді досить різко. Однак, принаймні на моє тестування та досвід, це досить незвично. Цілеспрямована оптимізація, в основному, або робить досить незначні відмінності, або може бути застосована (у будь-якому випадку автоматично) до досить конкретних типів проблем. Очевидно, що це могло б статися, якби ви запускали відносно стару програму на сучасній машині. Стара програма, написана на C ++, напевно, була б скомпільована до 32-розрядного коду і продовжувала б використовувати 32-розрядний код навіть на сучасному 64-розрядному процесорі. Програма, написана на C #, була б скомпільована в байтовий код, який потім ВМ скомпілювала б у 64-розрядний машинний код. Якби ця програма отримала значну вигоду від роботи в якості 64-розрядного коду, це могло б дати значну перевагу. За короткий час, коли 64-розрядні процесори були досить новими, цього трапилось немало. Останній код, який, ймовірно, виграє від 64-розрядного процесора, як правило, буде доступний, статично скомпільований у 64-розрядний код.

Використання віртуальної машини також має можливість покращити використання кешу. Інструкції для ВМ часто є більш компактними, ніж власні машинні інструкції. Більше з них може поміститися до заданого обсягу кеш-пам'яті, тому ви маєте більше шансів, що будь-який даний код буде в кеш-пам'яті, коли це потрібно. Це може допомогти зберегти інтерпретоване виконання коду віртуальної машини більш конкурентоспроможним (з точки зору швидкості), ніж більшість людей спочатку очікували - ви можете виконати багато інструкцій на сучасному центральному процесорі за час, який займає одна помилка кешу.

Варто також зазначити, що цей фактор взагалі не обов’язково відрізняється між собою. Ніщо не заважає (наприклад) компілятору C ++ видавати вихідні дані, призначені для роботи на віртуальній машині (з JIT або без нього). Насправді, C ++ / CLI від Microsoft є майже цим - (майже) відповідним компілятором C ++ (хоча і з великою кількістю розширень), який видає вихідні дані, призначені для роботи на віртуальній машині.

Зворотне також справедливо: Microsoft тепер має .NET Native, який компілює код C # (або VB.NET) до власного виконуваного файлу. Це дає продуктивність, яка, як правило, набагато більше схожа на C ++, але зберігає функції C # / VB (наприклад, C #, скомпільований у власний код, все ще підтримує відображення). Якщо у вас є інтенсивний код C #, це може бути корисно.

Вивіз сміття

З того, що я бачив, я б сказав, що збір сміття є найбіднішим з цих трьох факторів. Тільки для наочного прикладу, у запитанні тут згадується: "GC також не додає багато накладних витрат, якщо ви не створюєте та не знищуєте тисячі об'єктів [...]". Насправді, якщо створити та знищити тисячі об'єктів, накладні витрати на збір сміття, як правило, будуть досить низькими. .NET використовує генератор сміття, який є різновидом збирача копій. Колекціонер сміття працює, починаючи з "місць" (наприклад, реєстрів та стеку виконання), що відомі вказівники / посиланнябути доступним. Потім він "переслідує" ці вказівники на об'єкти, які були виділені в купі. Він досліджує ці об'єкти для подальших покажчиків / посилань, поки не пройшов за ними до кінців будь-яких ланцюжків, і не знайшов усіх об'єктів, які є (принаймні потенційно) доступними. На наступному кроці він бере всі об'єкти, які використовуються (або, принаймні, можуть бути ), і ущільнює купу, копіюючи всі їх у суміжний шматок на одному кінці пам'яті, якою управляється в купі. Решта пам'яті тоді вільна (модулі-фіналізатори потрібно запускати, але принаймні у добре написаному коді вони досить рідкісні, що я їх ігнорую на даний момент).

Це означає, що якщо ви створюєте та знищуєте багато об’єктів, збір сміття додає дуже мало накладних витрат. Час циклу вивезення сміття майже повністю залежить від кількості об’єктів, які були створені, але не знищені. Основним наслідком створення та знищення об’єктів поспіхом є просто те, що GC повинен працювати частіше, але кожен цикл все одно буде швидким. Якщо ви створюєте об'єкти і не знищуєте їх, GC запускатиметься частіше, і кожен цикл буде значно повільнішим, оскільки він витрачає більше часу, переслідуючи покажчики на потенційно діючі об'єкти, і витрачає більше часу на копіювання об'єктів, які все ще використовуються.

Для боротьби з цим винищення поколінь працює на припущенні, що об’єкти, які протягом деякого часу залишались «живими», ймовірно, продовжуватимуть залишатися живими ще деякий час. Виходячи з цього, у нього є система, коли об'єкти, які переживають деяку кількість циклів збору сміття, "стають", і збирач сміття починає просто припускати, що вони все ще використовуються, тому замість того, щоб копіювати їх на кожному циклі, він просто залишає їх поодинці. Це досить слушне припущення, що, як правило, видалення поколінь має значно нижчі накладні витрати, ніж у більшості інших форм ЖК.

"Ручне" управління пам'яттю часто настільки ж погано розуміється. Тільки для одного прикладу, багато спроб порівняння припускають, що все управління пам’яттю вручну також слідує одній конкретній моделі (наприклад, найкраще розподілене розподіл). Це часто мало (якщо взагалі є) ближче до реальності, ніж переконання багатьох людей щодо збору сміття (наприклад, поширене припущення, що це зазвичай робиться за допомогою підрахунку посилань).

З огляду на різноманітність стратегій як для збору сміття, так і для управління пам’яттю вручну, досить важко порівняти ці два за загальною швидкістю. Спроба порівняти швидкість розподілу та / або звільнення пам’яті (сама по собі) майже гарантовано дає результати, які в кращому випадку безглузді, а в гіршому - відверто оманливі.

Бонусна тема: Тести

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

Більшість з цих орієнтирів трохи схожі на підлітків, які вирішили змагатись на своїх автомобілях, і той, хто виграє, повинен зберегти обидва автомобілі. Хоча веб-сайти різняться одним вирішальним чином: вони, хто публікує еталон, отримують можливість їздити на обох автомобілях. Якимсь дивним випадком його машина завжди виграє, і всі інші повинні погодитися з тим, що "повірте мені, я справді їхав на вашій машині так швидко, як вона могла б піти".

Легко написати поганий орієнтир, який дає результати, які майже нічого не означають. Майже будь-хто, хто має будь-яку близьку майстерність, необхідну для розробки орієнтира, який дає щось значуще, також має навик створити той, який дасть результати, які він вирішив, що хоче. Насправді, напевно, простіше написати код для отримання конкретного результату, ніж той, який справді дасть значущі результати.

Як сказав мій друг Джеймс Канце, "ніколи не довіряйте еталону, який ви не фальсифікували самі".

Висновок

Простої відповіді немає. Я досить впевнений, що міг би перегорнути монету, щоб вибрати переможця, потім вибрати число від (скажімо) 1 до 20 для відсотка, на який вона виграє, і написати якийсь код, який виглядав би розумним і справедливим еталоном, і зробив такий упереджений висновок (принаймні на якомусь цільовому процесорі - інший процесор може трохи змінити відсоток).

Як зазначали інші, для більшості кодів швидкість майже не має значення. Наслідком цього (який набагато частіше ігнорується) є те, що в маленькому коді, де швидкість має значення, зазвичай це має велике значення . Принаймні на моєму досвіді, для коду, де це насправді важливо, С ++ майже завжди виграє. Безумовно, є фактори, які сприяють C #, але на практиці вони, здається, переважають фактори, що сприяють C ++. Ви, звичайно, можете знайти контрольні показники, які будуть вказувати на результат вашого вибору, але коли ви пишете реальний код, ви майже завжди можете зробити це швидше на C ++, ніж на C #. Для написання може знадобитися (а може і не бути) більше навичок та / або зусиль, але це практично завжди можливо.


6
У попередній компанії декілька наших рішень базувались на бенчмаркінгу, але бенчмаркінг був виконаний погано, оскільки він пропустив загальну картину (наприклад, вплив на ГК) або просто був погано виконаний. Остерігайтеся бенчмаркінгу ... спокусливо приймати рішення на основі речей, зроблених поза контекстом. Якщо ви робите бенчмарк, спробуйте зробити його якомога репрезентативнішим :)
Марк Сімпсон

4
Час виконання IIRC, .NET ніколи не інтерпретує, але завжди JIT. Оптимізація виконується як компілятором під час компіляції (вихідний код для IL), так і джиттером під час виконання (IL для власних інструкцій). Джиттер може вибрати не оптимізувати, якщо метод займе занадто багато часу для джиту. Якщо потрібна повна оптимізація, ви можете використовувати NGen для створення власного зображення під час встановлення.
Дуду,

2
Я думаю, що відповідь насправді досить проста: моя відповідь буде така: "Так, оскільки C # практично змушує вас робити структури даних еталонними типами, що додає новий рівень опосередкованості з кожним шаром обтікання, збільшуючи обсяг пам'яті та зменшуючи обсяг пам'яті. У C ++, незалежно від того, скільки шарів обтікання ви покладете навколо об'єкта, об'єкт залишиться в тому ж місці в пам'яті ". Ви згодні?
user541686

2
@Mehrdad: Так і ні. З практичної точки зору, так, це, швидше за все, важить на користь С ++ частіше. У той же час GC може полегшити просто передачу посилань, щоб у багатьох випадках уникнути копіювання даних.
Джеррі Коффін

2
@Mehrdad: Так - ось про те, про що я думав, про що я сказав: "Ви майже завжди можете зробити це швидше на C ++, ніж на C #. Для написання може знадобитися (а може і не бути) більше навичок та / або зусиль, але це практично завжди можливо ".
Джеррі Коффін,

41

Тому що вам не завжди потрібно користуватися (і я цим вільно) "найшвидшою" мовою? Я не їду на роботу у Ferrari лише тому, що це швидше ...


17
Я думаю, що ця аналогія дуже влучна. Якби я їздив на роботу «Феррарі», я б швидше не дістався до роботи. Автомобіль, звичайно, здатний їхати швидше, ніж те, що я їду, але здатність автомобіля не є обмежуючим фактором. Існують обмеження швидкості, дорожній рух, дорожні умови тощо. Подібним чином, програмне забезпечення, як правило, пов’язане з такими речами, як взаємодія користувачів, введення / виведення тощо. Яка мова, якою ви користуєтесь, не матиме великої різниці у таких випадках.
Фред Ларсон,

3
Ну, але питання було "Хто з автомобілів є Ferrari, а хто Volkswagen?" або якщо обидва є Ferrari чи ні.
pepr

@pepr Питання в заголовку полягає в тому, що так, але питання в кінці повідомлення "чому ви хочете використовувати Volkswagen, коли ви можете використовувати Ferrari?".
Адам Голдсворт,

@AdamHouldsworth: Так. Відповідь може бути схожою - "вартість має значення".
pepr

Ні, я їду на роботу на мотоциклі здебільшого тому, що він швидший.
CashCow

20

C ++ завжди має перевагу щодо продуктивності. З C # я не маю можливості обробляти пам’ять, і у мене є буквально маса ресурсів, якими я можу займатися своєю роботою.

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

Якщо існує обробка ядра, яка займає занадто багато часу в C #, тоді ви можете побудувати C ++ і інтегрувати свій шлях до нього за допомогою C #.

Перестаньте думати про роботу вашого коду. Почати будівельну вартість.


13
+1 за "Перестаньте думати про ефективність свого коду. Почніть будувати значення."
Thomas Matthews,

2
Я згоден щодо швидкості розробки на C #. Це набагато цінніше у багатьох випадках.
Йочай Тайммер,

Розробник потребує гарного вибору для кожного випадку. У деяких випадках C # не буде відповідати потребам. Припустімо програму, засновану на обчисленнях, таку як Video Converter, Video Mixer, 3D-віртуалізація, Flow Computation або гра . Також ви повинні зауважити, щоб проектувати цільове обладнання. Деяку програму потрібно запускати на низькому рівні HW.
SMMousavi

20

Приблизно у 2005 році два експерти з ефективності роботи з обох сторін рідного / керованого паркану намагалися відповісти на одне і те ж питання. Їх метод і процес все ще захоплюють, а висновки існують і сьогодні - і я не знаю жодної кращої спроби дати обґрунтовану відповідь. Вони зазначили, що обговорення потенційних причин відмінностей у результатах є гіпотетичним і марним, і справжнє обговорення повинно мати деяку емпіричну основу для реального впливу таких розбіжностей.

Отже, Старий Новий Реймонд Чен та Ріко Маріані встановлюють правила для товариського змагання. Як контекст іграшкових додатків було обрано китайсько-англійський словник: досить простий, щоб його можна було закодувати як допоміжний проект для хобі, але достатньо складний, щоб продемонструвати нетривіальні моделі використання даних. Правила почалися просто - Раймонд закодував просту реалізацію С ++, Ріко переніс її на С # рядок за рядком , без будь-якої вишуканості, і обидві реалізації виконали еталон. Потім відбулося кілька ітерацій оптимізації.

Повна інформація знаходиться тут: 1 , 2 , 3 , 4 , 5 , 6 , 7 , 8 , 9 , 10 , 11 , 12 , 13 , 14 .

Цей діалог титанів винятково освітній, і я від усієї душі рекомендую зануритися, але якщо вам не вистачає часу чи терпіння, Джефф Етвуд красиво склав нижчі рядки :

введіть тут опис зображення

Зрештою, C ++ був удвічі швидшим, але спочатку він був у 13 разів повільнішим.

Як підсумовує Ріко :

Тож чи соромно мені за мою нищівну поразку? Навряд чи. Керований код досягнув дуже хорошого результату майже навряд чи. Щоб перемогти керовану версію, Раймонду довелося:

  • Напишіть його власний файл / io матеріали

  • Напишіть його власний клас рядків

  • Напишіть його власний розподільник

  • Напишіть його власне міжнародне картографування

Звичайно, він використовував для цього доступні бібліотеки нижчого рівня, але це все ще багато роботи. Чи можете ви назвати те, що залишилось, програмою STL? Я не думаю.

Це мій досвід досі, 11 років, і хто знає, скільки версій C # / C ++ пізніше.

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


1
Це найкраща відповідь, і він прекрасно резюмує!
Родні П. Барбаті,

6

C # це швидше , ніж C ++. Швидше писати. Що стосується часу виконання, ніщо не може перевершити профіль.

Але C # не має стільки бібліотек, скільки C ++ може легко взаємодіяти.

А C # сильно залежить від вікон ...


5
C # вимагає набагато більшої підтримки компілятора, ОС та платформ. ВЕЛИЧЕЗНА турбота про вбудовані системи.
Thomas Matthews,

C # працює не тільки в Windows, але Mac, Linux, Android, iOS, ... див. Microsoft.com/net/multiple-platform-support , xamarin.com/platform , mono-project.com/docs/about-mono/ підтримувані платформи .
yoyo

@yoyo: C # дійсно працює на інших платформах (а в Linux також існував Mono), але бібліотеки, якими ви можете скористатися (наприклад, Windows Forms), можуть не працювати. Переносимість є проблемою для розробки C #.
Олександр К.

ця відповідь зараз змінена. Стандартна версія .NET в даний час офіційно підтримується для запуску на Linux від Microsoft. Отже, якщо вам не доведеться розробляти мікроконтролери, портативність - це не проблема. Не кажучи вже про те, що теж стало набагато швидше.
MovGP0

3

До речі, критично важливі для часу програми не кодуються на C # чи Java, головним чином через невизначеність того, коли буде здійснюватися Збір сміття.

У наш час швидкість застосування або виконання не настільки важлива, як раніше. Графік розробки, правильність та надійність є вищими пріоритетами. Високошвидкісна версія додатка не годиться, якщо у неї багато помилок, багато аварій або гірше, втрачає можливість вийти на ринок або бути розгорнутою.

Оскільки графіки розробки є пріоритетними, з’являються нові мови, які прискорюють розвиток. C # - один із таких. C # також допомагає в коректності та надійності, видаляючи з C ++ функції, які спричиняють загальні проблеми: один із прикладів - покажчики.

Різниця у швидкості виконання програми, розробленої на C #, та програми, розробленої з використанням C ++, є незначною на більшості платформ. Це пов’язано з тим, що вузькі місця виконання не залежать від мови, а зазвичай залежать від операційної системи або вводу-виводу. Наприклад, якщо C ++ виконує функцію за 5 мс, але C # використовує 2 мс, а очікування даних триває 2 секунди, час перебування у функції незначний порівняно з часом очікування даних.

Виберіть мову, яка найкраще підходить для розробників, платформи та проектів. Працюйте для досягнення цілей правильності, надійності та розгортання. Швидкість програми повинна трактуватися як помилка: розставити пріоритети, порівняти з іншими помилками та виправити за необхідності.


Я розумію, що C # (Java теж?) Не `` видаляє '' існування / концепцію покажчиків настільки, наскільки приховує їх від програміста шляхом абстрагування сортів за допомогою фактичного синтаксису. Однак це досить незначний момент. Відносна простота C # незаперечна.
Mike G

3

Кращий спосіб поглянути на це все повільніше, ніж C / C ++, оскільки він абстрагується, а не слідує парадигмі палиці та бруду. Це називається системним програмуванням з певної причини, ви програмуєте проти зерна або оголеного металу. Це також гарантує вам швидкість, якої ви не можете досягти за допомогою інших мов, таких як C # або Java. Але, на жаль, коріння C полягає в тому, щоб робити речі важко, тому ви в основному будете писати більше коду і витрачати більше часу на його налагодження.

C також чутливий до регістру, також об'єкти в C ++ також дотримуються суворих наборів правил. Приклад: фіолетовий конус морозива може бути не таким, як синій морозиво, хоча це можуть бути конуси, вони не обов'язково належать до сімейства конусів, і якщо ви забудете визначити, який конус ви виправляєте. Таким чином властивості морозива можуть бути або не бути клонами. Тепер аргумент швидкості, C / C ++ використовує стек і купу, тут оголений метал отримує його метал.

За допомогою бібліотеки boost ви можете досягти неймовірних швидкостей, на жаль, більшість ігрових студій дотримуються стандартної бібліотеки. Іншою причиною цього може бути те, що програмне забезпечення, написане на C / C ++, має великі розміри, оскільки це гігантська колекція файлів замість одного файлу. Також зверніть увагу, що всі операційні системи написані на мові C, тому загалом, чому ми повинні задавати питання, що може бути швидше ?!

Крім того, кешування не швидше, ніж чисте управління пам’яттю, вибачте, але це просто не роздувається. Пам'ять - це щось фізичне, кешування - це те, що робить програмне забезпечення для досягнення продуктивності. Можна також міркувати, що без фізичної пам’яті кешування просто не існувало б. Це не скасовує той факт, що пам’яттю потрібно керувати на якомусь рівні, будь то автоматизована чи ручна.


1

Чому б ви писали невелику програму, яка не вимагає багато оптимізації в C ++, якщо існує швидший маршрут (C #)?


Чому? Тому що я лох, щоб бачити, коли мій код працює. Включаючи деструктори. Навіть невеликий додаток отримує вигоду від оптимізації для читабельності.
IIСпецифічно

1

Отримати точну відповідь на своє питання насправді неможливо, якщо ви не виконуєте тести на конкретних системах. Проте цікаво подумати про деякі принципові відмінності між мовами програмування, такими як C # та C ++.

Компіляція

Виконання коду C # вимагає додаткового кроку, коли код має JIT'ed. Що стосується продуктивності, яка буде на користь С ++. Крім того, компілятор JIT здатний оптимізувати згенерований код в межах одиниці коду, яка є JIT'ом (наприклад, метод), тоді як компілятор C ++ може оптимізувати різні виклики методів, використовуючи більш агресивні методи.

Однак компілятор JIT здатний оптимізувати сформований машинний код, щоб точно відповідати базовому обладнанню, що дозволяє йому скористатися перевагами додаткових апаратних функцій, якщо вони існують. Наскільки мені відомо, компілятор .NET JIT цього не робить, але, можливо, він міг би генерувати інший код для Atom на відміну від процесорів Pentium.

Доступ до пам'яті

Архітектура зібраного сміття в багатьох випадках може створити більш оптимальні шаблони доступу до пам'яті, ніж стандартний код С ++. Якщо область пам'яті, яка використовується для першого покоління, досить мала, вона може залишатися в кеші процесора, збільшуючи продуктивність. Якщо ви створюєте та знищуєте багато дрібних об'єктів, накладні витрати на обслуговування керованої купи можуть бути меншими, ніж вимагає час виконання C ++. Знову ж таки, це сильно залежить від програми. Дослідження продуктивності Python демонструє, що конкретна керована програма Python здатна масштабуватися набагато краще, ніж скомпільована версія, в результаті більш оптимальних шаблонів доступу до пам'яті.


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

0

Нехай не бентежить!

  • Якщо програма C # написана в найкращому випадку, а програма C ++ написана в найкращому випадку, C ++ працює швидше.
    Тут багато причин про те, чому C ++ швидше, ніж C #, по суті, такий як C # використовує віртуальну машину, подібну до JVM в Java. В основному мова вищого рівня має меншу продуктивність (якщо використовується в кращому випадку).

  • Якщо ви досвідчений професійний програміст на C #, як і досвідчений професійний програміст на C ++, розробка програми за допомогою C # набагато легша і швидша, ніж на C ++.

Між цими ситуаціями можливо багато інших ситуацій. Наприклад, ви можете написати програму C # та програму C ++ так, щоб програма C # працювала швидше, ніж програма C ++.

Для вибору мови слід враховувати обставини проекту та його тематику. Для загального бізнес-проекту слід використовувати C #. Для проекту, що вимагає високої продуктивності, такого як відеоконвертер або проект обробки зображень, слід вибрати C ++.

Оновлення:

ГАРАЗД. Давайте порівняємо деякі практичні причини щодо того, чому максимально можлива швидкість C ++ більше, ніж C #. Розглянемо хороший письмовий додаток C # і ту саму версію C ++:

  • C # використовує віртуальну машину як середній рівень для запуску програми. Він має накладні витрати.
  • AFAIK CLR не може оптимізувати всі коди C # у цільовій машині. Програму C ++ можна скомпілювати на цільовій машині з найбільшою оптимізацією.
  • У C # максимально можлива оптимізація середовища виконання означає максимально можливу швидку віртуальну машину. ВМ і так має накладні витрати.
  • C # - мова вищого рівня, отже, вона генерує більше рядків програмного коду для остаточного процесу. (враховуйте різницю між додатком Assembly та Ruby! однакова умова є між C ++ та мовою вищого рівня, такою як C # / Java)

Якщо ви віддаєте перевагу отримати більше інформації на практиці як експерт, перегляньте це . Йдеться про Java, але це стосується і C #.


0

Основною проблемою була б не швидкість, а стабільність у версіях та оновленнях Windows. Win32 в основному захищений від версій Windows, що робить його стабільним.

Коли сервери виводяться з експлуатації та переносяться програмне забезпечення, виникає велика тривога навколо чого-небудь, що використовує .Net, і, як правило, багато паніки щодо версій .net, але програма Win32, побудована 10 років тому, просто працює, як нічого не сталося.


-1

Я спеціалізуюся на оптимізації близько 15 років і регулярно переписую код С ++, використовуючи якомога більше властивості компілятора, оскільки продуктивність С ++ часто далеко не така, на яку здатний процесор. Ефективність кешу часто потрібно враховувати. Для заміни стандартного коду з плаваючою комою на C ++ потрібно багато векторних інструкцій з математики. Значна частина коду STL переписується і часто працює в рази швидше. Математику та код, який інтенсивно використовує дані, можна переписати з вражаючими результатами, оскільки процесор наближається до своєї оптимальної продуктивності.

У C # нічого з цього неможливо. Порівняти їх відносну ефективність # реального часу # - це справді приголомшливо неосвічене питання. Найшвидшим фрагментом коду в C ++ буде, коли кожна окрема інструкція асемблера буде оптимізована для конкретного завдання, без зайвих інструкцій - взагалі. Де кожен фрагмент пам'яті використовується тоді, коли це потрібно, а не копіюється n разів, тому що цього вимагає мовний дизайн. Де кожен необхідний рух пам'яті працює в гармонії з кешем. Там, де остаточний алгоритм неможливо вдосконалити, виходячи з точних вимог реального часу, враховуючи точність та функціональність.

Тоді ви наблизитесь до оптимального рішення.

Порівняння C # з цією ідеальною ситуацією приголомшує. C # не може конкурувати. Насправді, я зараз переписую цілу купу коду C # (коли я кажу, що переписую, маю на увазі видалення та повну його заміну), оскільки він навіть не в тому самому місті, не кажучи вже про те, щоб зупинитися на балах, коли справа стосується важкого підйому в режимі реального часу продуктивність.

Тож, будь ласка, перестаньте себе дурити. C # повільний. Мертвий повільний. Усе програмне забезпечення гальмує, і C # погіршує цю швидкість. Усе програмне забезпечення працює за допомогою циклу виконання вибірки в асемблері (ви знаєте - на центральному процесорі). Ви використовуєте в 10 разів більше інструкцій; це буде йти в 10 разів повільніше. Ви скалічуєте кеш; це буде йти ще повільніше. Ви додаєте збір сміття до програмного забезпечення в режимі реального часу, тоді вас часто обманюють, думаючи, що код працює "добре", є лише ті кілька моментів, час від часу, коли код стає "трохи повільним на деякий час".

Спробуйте додати систему збору сміття до коду, де кожен цикл має значення. Цікаво, чи має програмне забезпечення для торгівлі на фондовому ринку збір сміття (ви знаєте - в системі, що працює на новому підводному кабелі, вартість якого 300 мільйонів доларів?). Чи можемо ми витратити 300 мілісекунд кожні 2 секунди? А як щодо програмного забезпечення для управління польотом на космічному шатлі - чи добре там GC? Як щодо програмного забезпечення для керування двигуном у високопродуктивних автомобілях? (Де перемога в сезоні може коштувати мільйони).

Вивіз сміття в режимі реального часу - повна невдача.

Так що ні, підкреслено, C ++ набагато швидший. C # - це стрибок назад.


1
C # не є стрибком назад, оскільки C # був розроблений із зовсім іншим набором вимог, ніж C ++. C # торгує швидкістю виконання на швидкість розвитку. Усі ті приклади, коли ви вказували, що C # не працює (космічні човники, управління двигуном тощо), ніколи не були цільовими програмами C #. C # дозволяє доставити готовий продукт відносно швидко. C # дозволяє продукту працювати на будь-якому обладнанні, на якому працює його віртуальна машина. Чи можете ви написати оптимізацію збірки, знаючи, що ваш код повинен працювати на сотні різних конфігурацій обладнання?
mag_zbc

Я погоджуюся з тим, що ви говорите mag_zbc, але початкове запитання було: "С # насправді повільніший, ніж скажімо C ++?" І мій коментар про "стрибок назад" стосувався швидкості C #, а не його переносимості.
Девід Ллойд,

Це упереджений погляд, який базується на чисто спекулятивних припущеннях, не надаючи жодних орієнтирів.
zmechanic
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.