Я собираюсь начать с несогласия с частью принятого (и хорошо оцененного) ответа на этот вопрос, заявив:
На самом деле существует множество причин, по которым код 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);
}
Время выполнения (выпуск): Инициализация: 398 мкс (да, это микросекунды), Заполнение: 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 ++ вы должны ... э-э, добраться до самостоятельно делать все эти выборы (и даже больше), в идеале, чтобы ваше решение наилучшим образом решало проблему, которую вы решаете.
Спросите себя, действительно ли вы хотите или нуждаетесь в этом элементе управления, потому что даже для приведенного выше тривиального примера вы можете видеть, что, несмотря на значительное улучшение производительности, для доступа к нему необходимы более глубокие инвестиции.