Я собираюсь начать с несогласия с частью принятого (и одобренного) ответа на этот вопрос, заявив:
На самом деле существует множество причин, по которым код JITted будет работать медленнее, чем правильно оптимизированная программа C ++ (или другой язык без накладных расходов времени выполнения), включая:
вычислительные циклы, затрачиваемые на код JITting во время выполнения, по определению недоступны для использования при выполнении программы.
любые горячие пути в JITter будут конкурировать с вашим кодом для инструкций и кэширования данных в CPU. Мы знаем, что кэш доминирует, когда дело доходит до производительности, и родные языки, такие как 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);
}
Время выполнения (выпуск): инициализация: 124мс, заполнение: 165мс
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 мкс (да, это микросекунды), Fill: 152 мс
Общее время выполнения: C #: 289 мс, C ++ 152 мс (примерно на 90% быстрее)
наблюдения
Изменение реализации C # на ту же реализацию 1d массива привело к Init: 40 мс, Fill: 171 мс, итого: 211 мс ( C ++ по-прежнему был почти на 40% быстрее ).
Проектировать и писать «быстрый» код на C ++ гораздо сложнее, чем писать «обычный» код на любом языке.
(Возможно) удивительно легко получить низкую производительность в C ++; мы видели это с незарезервированными векторами производительности. И таких ловушек много.
Производительность C # довольно впечатляет, если учесть все, что происходит во время выполнения. И эта производительность сравнительно легко доступна.
Дополнительные анекдотичные данные, сравнивающие производительность C ++ и C #: https://benchmarksgame.alioth.debian.org/u64q/compare.php?lang=gpp&lang2=csharpcore
Суть в том, что C ++ дает вам гораздо больший контроль над производительностью. Вы хотите использовать указатель? Ссылка? Стек памяти? Heap? Динамический полиморфизм или устранение накладных расходов во время выполнения виртуальной таблицы со статическим полиморфизмом (через шаблоны / CRTP)? В C ++ вы должны ... эр, получат сделать все эти выборы (и более) самостоятельно, в идеале , так что ваши решения лучших адреса проблема , которую вы Tackling.
Спросите себя, действительно ли вы хотите или нуждаетесь в таком контроле, потому что даже для приведенного выше простого примера вы можете видеть, что, хотя производительность значительно улучшается, для доступа к ней требуются более глубокие инвестиции.