Почну з того, що не погоджуюся з частиною прийнятої (і добре підкріпленої) відповіді на це питання, заявивши:
Насправді існує маса причин, чому JITted код буде працювати повільніше, ніж правильно оптимізована програма C ++ (або інша мова без накладних витрат), включаючи:
обчислювальні цикли, витрачені на JITting код під час виконання, за визначенням недоступні для використання у виконанні програми.
будь-які гарячі шляхи в JITter будуть конкурувати з вашим кодом за інструкціями та кешем даних в процесорі. Ми знаємо, що кеш домінує, коли мова йде про продуктивність, а рідні мови, такі як C ++, не мають такого типу суперечок, за визначенням.
Час бюджету оптимізатора часу виконання обов'язково значно обмежений, ніж бюджет оптимізатора часу компіляції (як вказував інший коментатор)
Підсумок: В кінцевому рахунку, ви будете майже напевно буде в змозі створити більш швидку реалізацію в C ++ , ніж ви могли б в C # .
Тепер, маючи на увазі сказане, наскільки швидше насправді неможливо оцінити, оскільки є занадто багато змінних: завдання, проблемний домен, обладнання, якість реалізації та багато інших факторів. Ви будете проводити тести свого сценарію, щоб визначити різницю в продуктивності, а потім вирішите, чи варто додаткового зусилля та складності.
Це дуже довга і складна тема, але я вважаю, що варто згадати заради повноти, що оптимізатор виконання C # є відмінним і здатний виконувати певні динамічні оптимізації під час виконання, які просто недоступні для C ++ за час його компіляції ( статичний) оптимізатор. Навіть при цьому перевага все ще є глибоко в суді нашої програми, але динамічний оптимізатор є причиною " майже класифікатора напевно", наведеного вище.
-
Щодо відносної продуктивності, мене також турбували цифри та дискусії, які я бачив у деяких інших відповідях, тому я думав, що я би задзвонив і, в той же час, надати певну підтримку висловленим вище твердженням.
Величезна частина проблеми з цими орієнтирами полягає в тому, що ви не можете записати код C ++ так, як ніби ви писали C #, і очікуєте отримати репрезентативні результати (наприклад, виконання тисяч розподілу пам'яті в C ++ дасть вам жахливі цифри.)
Натомість я написав трохи більше ідіоматичного коду C ++ і порівняв із наданим кодом C # @Wiory. Дві основні зміни, внесені до коду C ++, були:
1) використаний вектор :: резерв ()
2) розрівняли 2d масив до 1d для досягнення кращої локальності кешу (суміжний блок)
C # (.NET 4.6.1)
private static void TestArray()
{
const int rows = 5000;
const int columns = 9000;
DateTime t1 = System.DateTime.Now;
double[][] arr = new double[rows][];
for (int i = 0; i < rows; i++)
arr[i] = new double[columns];
DateTime t2 = System.DateTime.Now;
Console.WriteLine(t2 - t1);
t1 = System.DateTime.Now;
for (int i = 0; i < rows; i++)
for (int j = 0; j < columns; j++)
arr[i][j] = i;
t2 = System.DateTime.Now;
Console.WriteLine(t2 - t1);
}
Час виконання (реліз): Init: 124ms, Заповнення: 165ms
C ++ 14 (Clang v3.8 / C2)
#include <iostream>
#include <vector>
auto TestSuite::ColMajorArray()
{
constexpr size_t ROWS = 5000;
constexpr size_t COLS = 9000;
auto initStart = std::chrono::steady_clock::now();
auto arr = std::vector<double>();
arr.reserve(ROWS * COLS);
auto initFinish = std::chrono::steady_clock::now();
auto initTime = std::chrono::duration_cast<std::chrono::microseconds>(initFinish - initStart);
auto fillStart = std::chrono::steady_clock::now();
for(auto i = 0, r = 0; r < ROWS; ++r)
{
for (auto c = 0; c < COLS; ++c)
{
arr[i++] = static_cast<double>(r * c);
}
}
auto fillFinish = std::chrono::steady_clock::now();
auto fillTime = std::chrono::duration_cast<std::chrono::milliseconds>(fillFinish - fillStart);
return std::make_pair(initTime, fillTime);
}
Час виконання (реліз): Init: 398 мкс (так, це мікросекунди), заповнення: 152 мс
Загальний час роботи: C #: 289 мс, С ++ 152 мс (приблизно на 90% швидше)
Спостереження
Якщо змінити реалізацію C # на ту саму реалізацію 1d масиву, вийшло Init: 40ms, Fill: 171ms, Total: 211ms ( C ++ все ще майже на 40% швидше ).
Набагато складніше сконструювати та записати "швидкий" код на C ++, ніж написати "звичайний" код на будь-якій мові.
(Можливо) дивно легко отримати низьку продуктивність в C ++; ми це бачили з беззастережною продуктивністю векторів. І є безліч таких підводних каменів.
Продуктивність C # досить дивовижна, якщо врахувати все, що відбувається під час виконання. І до цієї продуктивності порівняно легко дістатися.
Більше анекдотичних даних, що порівнюють ефективність C ++ та C #: https://benchmarksgame.alioth.debian.org/u64q/compare.php?lang=gpp&lang2=csharpcore
Суть полягає в тому, що C ++ дає вам набагато більше контролю над роботою. Ви хочете використовувати вказівник? Довідка? Стек пам'яті? Купи? Динамічний поліморфізм чи усунення накладних витрат вітла зі статичним поліморфізмом (за допомогою шаблонів / CRTP)? У C ++ ви повинні ... ер, дістатися зробити всі ці вибори (і більше) самостійно, в ідеалі , так що ваші рішення кращих адреси проблема , яку ви Tackling.
Запитайте себе, чи дійсно ви хочете чи потребуєте цього контролю, адже навіть на банальному прикладі, наведеному вище, ви бачите, що, хоча є значне поліпшення продуктивності, воно потребує більш глибоких інвестицій для доступу.