Насколько быстрее C ++, чем C #?

246

Или сейчас все наоборот?

Из того, что я слышал, есть некоторые области, в которых C # оказывается быстрее, чем C ++, но у меня никогда не хватало смелости проверить это самостоятельно.

Думаю, что любой из вас мог бы подробно объяснить эти различия или указать мне правильное место для информации об этом.

ловушка
источник
7
Защищено, чтобы предотвратить появление каких-либо случайных ориентиров. Если вы думаете, что можете сделать свое дело, вам понадобится 10 повторений для этого.
Роберт Харви
2
Как это не закрыто как мнение / аргументация в любом случае? Разве я еще не на StackOverflow? (Не предлагая близко, просто любопытно. Мне нравятся вопросы, которые стимулируют аргументированные аргументы)
Билл К
1
Это почти спорный вопрос, учитывая, что мы живем в эпоху, когда IL можно преобразовать в CPP и оттуда оптимизировать: docs.unity3d.com/Manual/IL2CPP.html
pixelpax
Язык, который проверяет доступ к массиву вне диапазона, никогда не превзойдет того, который не делает.
Сева Алексеева
@SevaAlekseyev Это делает не язык, а компилятор. Одна из причин того, что C ++ так быстро (кроме очевидных), заключается в том, что компиляторы C ++ существуют уже 35 лет (если не больше). Ничто не мешает компиляторам C # со временем улучшаться. Для случая, о котором вы упомянули, пожалуйста, прочитайте этот stackoverflow.com/questions/16713076/…
Trap

Ответы:

343

Нет строгой причины, по которой язык на основе байт-кода, такой как C # или Java, имеющий JIT, не может быть таким же быстрым, как код C ++. Однако код C ++ долгое время был значительно быстрее, а также сегодня во многих случаях. Это происходит главным образом из-за того, что более сложные JIT-оптимизации сложны для реализации, а действительно крутые из них появляются только сейчас.

Так что C ++ во многих случаях быстрее. Но это только часть ответа. Случаи, когда C ++ на самом деле быстрее, - это программы с высокой степенью оптимизации, где опытные программисты тщательно оптимизируют код. Это не только очень много времени (и, следовательно, дорого), но также часто приводит к ошибкам из-за чрезмерной оптимизации.

С другой стороны, код на интерпретируемых языках становится быстрее в более поздних версиях среды выполнения (.NET CLR или Java VM) без каких-либо действий. И есть много полезных оптимизаций, которые JIT-компиляторы могут сделать, что просто невозможно в языках с указателями. Кроме того, некоторые утверждают, что сборка мусора, как правило, должна быть такой же быстрой или быстрой, как ручное управление памятью, и во многих случаях это так. Как правило, все это можно реализовать и реализовать на C ++ или C, но это будет намного сложнее и подвержено ошибкам.

Как сказал Дональд Кнут, «преждевременная оптимизация - корень всего зла». Если вы действительно точно знаете, что ваше приложение будет в основном состоять из арифметики, очень критичной к производительности, и что это будет узким местом, и оно наверняка будет быстрее в C ++, и вы уверены, что C ++ не будет конфликтовать с другими требования, перейти на C ++. В любом другом случае сначала сконцентрируйтесь на правильной реализации приложения на любом языке, который вам больше подходит, затем найдите узкие места в производительности, если он работает слишком медленно, а затем подумайте о том, как оптимизировать код. В худшем случае вам может потребоваться обратиться к коду C через интерфейс сторонней функции, поэтому у вас все еще будет возможность писать критические части на языке более низкого уровня.

Имейте в виду, что оптимизировать правильную программу относительно легко, но гораздо труднее исправить оптимизированную программу.

Дать фактический процент преимуществ скорости невозможно, это во многом зависит от вашего кода. Во многих случаях реализация языка программирования даже не является узким местом. Взять тесты на http://benchmarksgame.alioth.debian.org/ с большим скептицизмом, так как они во многом тестируют арифметический код, который, скорее всего, совсем не похож на ваш код.

Мартин Пробст
источник
92
<quote> код на интерпретируемых языках становится быстрее в более поздних версиях среды выполнения </ quote> Поскольку код, скомпилированный лучшей версией компилятора, также будет работать быстрее.
Мартин Йорк,
47
На самом деле есть хотя бы одна причина: JIT должен быть быстрым и не может позволить себе тратить время на различные дополнительные оптимизации, доступные для компилятора C ++.
Неманя Трифунович
63
«но также обычно приводит к ошибкам из-за чрезмерной оптимизации». [цитата крайне необходима]. Я работаю в национальной лаборатории, и мы чертовски оптимизируем наш код. Это обычно не приводит к ошибочному коду.
Тодд Гамблин
35
«Оптимизировать правильную программу относительно легко, но гораздо труднее исправить оптимизированную программу».
gradbot
20
Инге: не уверена, что вы на правильном пути. Да, C # реализован на другом языке, но JIT-компилятор генерирует машинный код, поэтому это не интерпретируемый язык. Таким образом, он не ограничен реализацией C ++. Я не совсем уверен, почему вы думаете, что добавление какого-то менеджера по своей сути делает это быстрее.
Мартин Пробст
202

C # не может быть быстрее, но делает вас / меня быстрее. Это самая важная мера для того, что я делаю. :)

mattlant
источник
68
Ха-ха, есть хорошая цитата Ларри Уолла на эту тему. Он говорит о Perl, но об этом можно подумать во всех обсуждениях, связанных с языками и производительностью: «... более ранние компьютерные языки, такие как Fortran и C, были разработаны для эффективного использования дорогостоящего компьютерного оборудования. В отличие от Perl предназначен для эффективно использовать дорогих программистов »
Фалаина
60
1. «C # намного быстрее, чем C ++» 2. «Это не может быть правдой» 1. «Конечно, может» 2. «На сколько?» 1. «Обычно на 3-4 месяца»
Дмитрий Сергеевич
2
для C ++, который действительно зависит от используемых вами библиотек, C # обычно не быстрее, а .NET - когда вы говорите о производительности
Ion Todirel
По той же причине вы можете использовать Python вместо C для написания некоторого кода ... но после создания некоторых сложных вычислений вы можете почувствовать разницу в производительности.
Ch3shire
Это зависит от того, что вы привыкли. Я программирую на C ++ намного быстрее, чем на C #. Знание библиотеки - большая часть этого, так как вы не хотите изобретать велосипед для базовых задач. Основной проблемой C / C ++ было управление указателями, которое в значительной степени решается с помощью умных указателей. Сказав, что C ++ серьезно не хватает обширной библиотеки, как предлагают .NET и Java, и это может значительно ускорить разработку. Это не будет решено в ближайшее время, так как эти ребята предпочитают тратить свое время на улучшение шаблонов, а не на расширение библиотек.
gast128
87

Это пять апельсинов быстрее. Или скорее: не может быть (правильного) общего ответа. C ++ - это статически скомпилированный язык (но, кроме того, есть и оптимизация по профилю), C # запускается с помощью JIT-компилятора. Существует так много различий, что на такие вопросы, как «насколько быстрее» нельзя ответить, даже задавая порядки.

Конрад Рудольф
источник
177
Есть ли у вас какие-либо доказательства в поддержку вашего возмутительного заявления о пяти апельсинах? Все мои эксперименты указывают на максимум 2 апельсина, с улучшением манго на 3 при выполнении шаблонного метапрограммирования.
Алекс
42
На дрожжах он не утверждает, что закуски быстрее.
Крис
11
Из моего опыта это скорее 5,2 апельсины. Но это зависит от используемого вами фруктового метра.
Дио Ф
4
Обновление, сам StackOverflow испортил и обрабатывает комментарии неэффективно, поэтому меньше бананов (300 бананов хуже, чем должно быть): meta.stackexchange.com/questions/254534/…
KeksArmee
87

Я собираюсь начать с несогласия с частью принятого (и одобренного) ответа на этот вопрос, заявив:

На самом деле существует множество причин, по которым код 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.

Спросите себя, действительно ли вы хотите или нуждаетесь в таком контроле, потому что даже для приведенного выше простого примера вы можете видеть, что, хотя производительность значительно улучшается, для доступа к ней требуются более глубокие инвестиции.

U007D
источник
16
@Quonux спасибо за комментарий. Конечно, это не «настоящая программа». Смысл тестов заключался в рефакторинге эталонного теста C #, предлагаемого в другом месте на этой странице, в качестве доказательства того, что код JITted несколько быстрее, чем нативный - это не так, и этот тест потенциально вводил в заблуждение новых людей.
U007D
9
@Quonux, почему ты так пишешь? Такие люди, как ты, заставляют меня не любить stackoverflow.
Маркус Кнаппен Йоханссон
5
@MarkusKnappenJohansson У меня был плохой день;), я тоже просто человек, убрал свое отрицательное мнение, но мое мнение все еще применимо. О, пожалуйста, не любите ТАК только потому, что есть некоторые "глупые" люди :). Хорошего вам.
Quonux
9
ПОЛНОСТЬЮ РАЗМЕЩАЮЩИЙСЯ ЭТАЛОН В версии C ++ вы просто резервируете часть памяти (и затем удивляетесь, как на выполнение этой операции уходят микросекунды). В версии C # вы создаете 5000 массивов (создание экземпляров объектов в памяти). C ++ быстрее, чем C # ... но разница не превышает 40% ... сейчас она больше в диапазоне <10%. Ваш пример иллюстрирует, что программисты должны придерживаться языка по своему выбору (и из вашего профиля очевидно, что вы программист на C ++). В C # вы можете сделать 2D массив int[,]... следуя примеру.
nikib3ro
3
Из того, что я могу сказать, код в вашем примере C ++ буквально просто выделяет память раньше времени. Реализация PROPER C # просто напишет «List <double> arrs = new List <double> (ROWS * COLS)», который выделяет память, необходимую для индексации двумерного массива в одномерном формате (например, то, что вы делали в C ++). Нет абсолютно никакой причины выделять двумерный массив и сглаживать его вручную - огромное количество итераций в вашем предварительном тесте является причиной дерьмовой производительности. Я полагаю, что издержки все еще будут больше в C #, но не на значительную сумму.
JDSweetBeat
62

По моему опыту (и я много работал с обоими языками), главная проблема с C # по сравнению с C ++ - это высокое потребление памяти, и я не нашел хорошего способа управления им. Именно потребление памяти в конечном итоге замедлит работу программного обеспечения .NET.

Другим фактором является то, что JIT-компилятор не может позволить себе слишком много времени для выполнения расширенных оптимизаций, потому что он работает во время выполнения, и конечный пользователь заметит это, если это займет слишком много времени. С другой стороны, компилятор C ++ имеет все время, необходимое для оптимизации во время компиляции. Этот фактор гораздо менее значим, чем потребление памяти, ИМХО.

Неманья Трифунович
источник
6
В одном работающем проекте нам пришлось добывать гигантские объемы данных, включая одновременное хранение большого количества ГБ в памяти и выполнение дорогостоящих вычислений для всего этого - для этого требовался точный контроль всех выделений, C ++ был практически единственным выбором. +1 для C ++. С другой стороны, это был всего лишь один проект, мы потратили большую часть нашего времени на написание систем, взаимодействующих с медленными симуляторами, и отладка могла бы стать кошмаром, поэтому мне хотелось бы, чтобы мы могли использовать язык, оптимизирующий время программиста, для всего остального вещи.
Богатырь
7
@IngeHenriksen: я хорошо знаю шаблон Dispose, но он совсем не помогает с управляемой памятью.
Неманя Трифунович
10
@IngeHenriksen, удаляя его, только гарантирует, что был вызван метод Dispose. Утилизация никогда не освобождает память, собранную мусором. Метод Dispose предназначен только для очистки неуправляемых ресурсов, таких как файловые дескрипторы, и не имеет никакого отношения к управлению памятью.
doug65536
1
@NemanjaTrifunovic: «JIT-компилятор не может позволить себе слишком много времени для продвинутой оптимизации». Можете ли вы привести некоторые оптимизации, которые не выполняются JIT, потому что это займет слишком много времени?
Джон Харроп
5
@ user3800527: Даже если добавление ОЗУ всегда возможно (а это не так - представьте, что Microsoft добавляет ОЗУ каждому пользователю MS Office), это не решит проблему. Память является иерархической, и у программы на C # будет гораздо больше ошибок в кэше, чем на C ++.
Неманя Трифунович
35

Один конкретный сценарий, в котором C ++ по-прежнему имеет преимущество (и будет в ближайшие годы), возникает, когда полиморфные решения могут быть заранее определены во время компиляции.

Как правило, инкапсуляция и отложенное принятие решений - это хорошая вещь, потому что они делают код более динамичным, легче адаптируются к изменяющимся требованиям и легче используются в качестве основы. Вот почему объектно-ориентированное программирование на C # очень продуктивно и его можно обобщить под термином «обобщение». К сожалению, этот конкретный тип обобщения обходится во время выполнения.

Обычно эта стоимость несущественна, но есть приложения, в которых накладные расходы на вызовы виртуальных методов и создание объектов могут иметь значение (особенно потому, что виртуальные методы предотвращают другие оптимизации, такие как встраивание вызовов методов). Именно здесь C ++ имеет огромное преимущество, потому что вы можете использовать шаблоны для достижения другого вида обобщения, который не влияет на время выполнения, но не обязательно является менее полиморфным, чем ООП. Фактически, все механизмы, которые составляют ООП, могут быть смоделированы с использованием только шаблонных методов и разрешения во время компиляции.

В таких случаях (и по общему признанию, они часто ограничены специальными проблемными областями), C ++ выигрывает у C # и сопоставимых языков.

Конрад Рудольф
источник
6
На самом деле, виртуальные машины Java (и, возможно, .NET) идут на все, чтобы избежать динамического распределения. По сути, если есть способ избежать полиморфимов, вы можете быть уверены, что ваша виртуальная машина это сделает.
Мартин Пробст
3
+1 У меня всегда есть проблемы с объяснением этого моим коллегам по C #, которые знают немного C ++ таким образом, чтобы они могли оценить значение. Вы объяснили это довольно мило.
Роман Старков
9
@ Crtracy: вы делаете ставку без высокопроизводительных вычислительных приложений. Рассмотрим прогноз погоды, биоинформатику и численное моделирование. Повышение производительности C ++ в этих областях не уменьшится, потому что никакой другой код не может достичь сопоставимой производительности при том же уровне высокой абстракции.
Конрад Рудольф
5
@Jon Яблоки и апельсины. Вы указали, что «C # на несколько порядков быстрее, чем C ++ в контексте метапрограммирования», а не «использование предварительно скомпилированного кода на несколько порядков быстрее, чем интерпретируемый код». Несмотря на это, ваше утверждение о том, что генерация кода во время выполнения является «более общей», чем генерация кода во время компиляции, также явно неверно - у них есть как сильные, так и слабые стороны. Генерация кода во время компиляции использует систему типов для обеспечения безопасности статического типа - генерация кода во время выполнения не может этого сделать (она может обеспечить строгую безопасность типа, но не безопасность статического типа).
Конрад Рудольф
5
@ user3800527 Я думаю, что вы упускаете суть этого ответа. Конечно, вы можете обойти это, нарушив инкапсуляцию и опустившись до низкоуровневых структур - вы можете написать ассемблер на (большинстве) любом языке. То, что делает C ++ (почти) уникальным и уникально подходящим для высокопроизводительного программирования, заключается в том, что вы можете создавать высокоуровневые абстракции, которые не требуют затрат времени выполнения. Поэтому вам не нужно писать подобный ассемблеру код на C ++, чтобы получить превосходную производительность: хорошо написанный текст sort(arr, generic_comparer)будет столь же эффективен, как и рукописный цикл на C ++. Этого никогда не будет в C #.
Конрад Рудольф
20

C ++ (или C в этом отношении) дает вам детальный контроль над вашими структурами данных. Если вы хотите немного покататься, у вас есть такая опция. Большие управляемые приложения Java или .NET (OWB, Visual Studio 2005 ), которые используют внутренние структуры данных библиотек Java / .NET, несут с собой багаж. Я видел сеансы OWB-дизайнеров, использующие более 400 МБ ОЗУ и BIDS для куба или ETL- дизайна, также доходящие до сотен МБ.

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

IMO в больших приложениях, разница не столько в JIT, сколько в структурах данных, которые использует сам код. Если приложение занимает много памяти, вы получите менее эффективное использование кэша. Промах кэша на современных процессорах довольно дорогой. Где C или C ++ действительно выигрывают, так это то, где вы можете оптимизировать использование структур данных, чтобы хорошо играть с кэшем ЦП.

ConcernedOfTunbridgeWells
источник
19

Для графики стандартный класс C # Graphics намного медленнее, чем GDI, доступ к которому осуществляется через C / C ++. Я знаю, что это не имеет ничего общего с языком как таковым, больше с общей платформой .NET, но графика - это то, что предлагается разработчику в качестве замены GDI, а ее производительность настолько плоха, что я даже не посмел бы делать графику с этим.

У нас есть простой тест, который мы используем, чтобы увидеть, насколько быстро работает графическая библиотека, и это просто рисование случайных линий в окне. C ++ / GDI по-прежнему быстры с 10000 строками, в то время как C # / Graphics с трудом делает 1000 в режиме реального времени.

QBziZ
источник
5
Я был заинтригован вашим ответом. Вы тестировали один и тот же эталонный тест с небезопасным кодом и блоками блокировок и сами рисовали случайные линии? Теперь это было бы интересно посмотреть.
Педери
2
@ Педери Нет, у меня нет. просто используя GDI и .NET.Graphics самым простым способом. что вы подразумеваете под "рисованием случайных линий самостоятельно"?
QBziZ
1
Тогда вам, возможно, стоит подумать о том, чтобы протестировать это, чтобы получить более реалистичные метрики того, насколько быстрым может быть C #. Вот хороший обзор техники: bobpowell.net/lockingbits.htm
Педери
6
Это не то, что мы хотим сделать, помещая отдельные пиксели в буфер кадра самостоятельно. Если вам нужно все реализовать самостоятельно, какой смысл иметь API / платформу для кодирования? Для меня это не аргумент. Нам никогда не требовалось помещать отдельные пиксели в кадровый буфер в GDI для рисования линий, и мы не планируем делать это и в .NET. На мой взгляд, мы использовали реалистичную метрику, а .NET оказался медленным.
QBziZ
1
Ну, у меня есть небольшое представление о том, что такое обнаружение BLOB-объектов, но просто указание одного времени скорее ничего не доказывает. Вы написали один на C ++? В JavaScript? И сравнили те, что в C #? И кроме того, я не думаю, что для обнаружения BLOB-объектов используется много графических примитивов. Поправьте меня, если не прав, но я предполагаю, что статистические алгоритмы выполняют операции над пикселями.
QBziZ
13

Сборка мусора является основной причиной, по которой Java # НЕ МОЖЕТ использоваться для систем реального времени.

  1. Когда произойдет GC?

  2. Как много времени это займет?

Это недетерминировано.


источник
5
Я не большой поклонник Java, но ничто не говорит о том, что Java не может использовать дружественный GC в реальном времени.
Zan Lynx
5
Есть много реализаций GC в реальном времени, если вы хотите посмотреть. (GC - область, переполненная исследовательскими работами)
Арафангион
FWIW, Ричард Джонс только что опубликовал обновленную версию своей книги по сбору мусора, которая охватывает, помимо прочего, самые современные разработки GC в реальном времени.
Джон Харроп
11
Это бессмысленный аргумент, Windows (и Linux) не являются операционными системами реального времени. Ваш код C ++ может быть заменен на количество слотов 18 мс в любое время.
Хенк Холтерман
2
@HenkHolterman Верно, но вы всегда можете написать загрузчик в сборке, связать его с загрузчиком ядра для вашего приложения и запускать ваши приложения на C ++ непосредственно против аппаратного обеспечения (в RT, кстати). Вы не можете сделать это в C #, и любые попытки, которые я видел, имитируют только скомпилированную сборку в C # и используют тонну кода C, что делает бессмысленным использование C #. Читать все это довольно забавно, потому что C # действительно бесполезен без .NET Framework.
zackery.fix
11

Мы должны были определить, был ли C # сопоставим по производительности с C ++, и я написал несколько тестовых программ для этого (используя Visual Studio 2005 для обоих языков). Оказалось, что без сборки мусора и только с учетом языка (не фреймворка) C # имеет в основном ту же производительность, что и C ++. Выделение памяти намного быстрее в C #, чем в C ++, и C # имеет небольшое преимущество в детерминизме, когда размеры данных превышают границы строк кэша. Однако за все это в конечном итоге пришлось заплатить, и это приводит к огромным затратам в виде недетерминированных падений производительности для C # из-за сбора мусора.

ILoveFortran
источник
1
В C ++ у вас есть возможность использовать разные методы выделения, поэтому в зависимости от того, как была выделена память (AOT?) В C #, это можно сделать так же (но гораздо быстрее) в C ++.
zackery.fix
5
@ zackery.fix .NET имеет интересное преимущество в распределении кучи, потому что ему нужно только переместить указатель для выделения нового объекта. Это возможно только благодаря компактному сборщику мусора. Конечно, вы можете сделать то же самое в C ++, но C ++ этого не делает. Забавно, когда вы используете один и тот же аргумент, чтобы сказать: «C # может, но не может, так что это мусор» и «C ++ нет, но может, так здорово» :)
Luaan
9

Как обычно, это зависит от приложения. Есть случаи, когда C #, вероятно, ничтожно медленнее, и другие случаи, когда C ++ работает в 5 или 10 раз быстрее, особенно в тех случаях, когда операции могут быть легко выполнены SIMD.

Темный Шикари
источник
Наилучшим вариантом для виртуальных машин будет компиляция сгенерированного кода во время выполнения (например, для сопоставления с регулярным выражением, считываемым во время выполнения), потому что статически скомпилированные программы vanilla C ++ могут использовать только интерпретацию, поскольку в них не встроен JIT-компилятор.
Джон Харроп
Примечание из будущего: .NET поддерживает SIMD и друзей примерно с 2014 года, хотя и не широко используется.
Луаан
9

Я знаю, что это не то, о чем вы спрашивали, но C # часто пишется быстрее, чем C ++, что является большим бонусом в коммерческой среде.

Kramii
источник
2
Я бы сказал, что в большинстве случаев это быстрее :)
Trap
8

C / C ++ может работать намного лучше в программах, где есть либо большие массивы, либо тяжелые циклы / итерации по массивам (любого размера). Это причина того, что графика обычно намного быстрее в C / C ++, потому что тяжелые операции с массивами лежат в основе почти всех графических операций. .NET известен своей медлительностью в операциях индексации массивов из-за всех проверок безопасности, и это особенно верно для многомерных массивов (и, да, прямоугольные массивы C # даже медленнее, чем зубчатые массивы C #).

Бонусы C / C ++ наиболее заметны, если вы придерживаетесь указателей и избегаете Boost std::vectorи других высокоуровневых контейнеров, а также inlineлюбой возможной небольшой функции. По возможности используйте массивы старой школы. Да, вам потребуется больше строк кода, чтобы выполнить то же самое, что вы сделали в Java или C #, так как вы избегаете высокоуровневых контейнеров. Если вам нужен массив динамического размера, вам просто нужно помнить, чтобы связать ваш new T[]с соответствующим delete[]оператором (или использоватьstd::unique_ptr) - цена за дополнительную скорость заключается в том, что вы должны кодировать более тщательно. Но в обмен на это вы избавляете себя от накладных расходов на управляемую память / сборщик мусора, которые могут легко составлять 20% или более времени выполнения сильно ориентированных на объект программ как на Java, так и на .NET, а также массивных управляемых программ. затраты на индексацию массива памяти. Приложения C ++ также могут извлечь выгоду из некоторых изящных переключателей компилятора в определенных конкретных случаях.

Я опытный программист на C, C ++, Java и C #. Недавно у меня был редкий случай реализовать точно такую ​​же алгоритмическую программу на последних 3 языках. В программе было много математических и многомерных операций с массивами. Я сильно оптимизировал это на всех 3 языках. Результаты были типичными для того, что я обычно вижу в менее строгих сравнениях: Java была примерно в 1,3 раза быстрее, чем C # (большинство JVM более оптимизированы, чем CLR), а версия необработанного указателя на C ++ оказалась примерно в 2,1 раза быстрее, чем C #. Обратите внимание, что программа C # использовала только безопасный код - я считаю, что вы могли бы также написать код на C ++ перед использованием unsafeключевого слова.

Чтобы никто не думал, что я что-то имею против C #, я в заключение скажу, что C #, вероятно, мой любимый язык. Это самый логичный, интуитивно понятный и быстрый язык разработки, с которым я когда-либо сталкивался. Я делаю все свои прототипы в C #. Язык C # имеет много небольших и тонких преимуществ по сравнению с Java (да, я знаю, что у Microsoft была возможность исправить многие недостатки Java, войдя в игру с опозданием и, возможно, скопировав Java). Тост за Calendarкласс Java кто-нибудь? Если Microsoft когда-либо приложит реальные усилия для оптимизации CLR и .NET JITter, C # может серьезно вступить во владение. Я, честно говоря, удивлен, что они этого еще не сделали - они так много сделали прямо на языке C #, почему бы не сделать это с помощью мощных оптимизаций компилятора? Может быть, если мы все умоляем.

Специальный соус
источник
3
«вам просто нужно помнить, чтобы соединить ваш new T[]с соответствующим delete[]» - нет, вы не делаете. Там std::unique_ptrсделать это для вас.
Эмлай
если вы написали что-то в графике, зачем писать безопасный код на c #, не задумывались ли вы об использовании небезопасного кода и сравниваете снова?
user3800527
7

> Из того, что я слышал ...

Похоже, ваша трудность заключается в том, чтобы решить, является ли то, что вы услышали, достоверным, и эта проблема будет повторяться, когда вы попытаетесь оценить ответы на этом сайте.

Как вы решите, что люди говорят здесь более или менее достоверно, чем то, что вы изначально слышали?

Одним из способов было бы попросить доказательства .

Когда кто-то утверждает, что «есть области, в которых C # оказывается быстрее, чем C ++», спросите его, почему они так говорят , попросите его показать вам измерения, попросите их показать вам программы. Иногда они просто ошиблись. Иногда вы обнаружите, что они просто выражают мнение, а не делятся тем, что они могут показать, чтобы быть правдой.

Часто информация и мнение будут смешиваться в том, что люди утверждают, и вам придется попытаться выяснить, что есть что. Например, из ответов на этом форуме:

  • «Взять тесты на http://shootout.alioth.debian.org/ с большим скептицизмом, так как они во многом тестируют арифметический код, который, скорее всего, совсем не похож на ваш код».

    Спросите себя, действительно ли вы понимаете, что означает «этот в основном тестовый арифметический код» , а затем спросите себя, действительно ли автор показал вам, что его утверждение верно.

  • «Это довольно бесполезный тест, поскольку он действительно зависит от того, насколько хорошо были оптимизированы отдельные программы; мне удалось ускорить некоторые из них в 4–6 раз или более, давая понять, что сравнение между неоптимизированными программами довольно глупо «.

    Спросите себя, действительно ли автор показал вам, что ему удалось «ускорить некоторые из них в 4-6 раз или больше» - это легко сделать!

Питер Мортенсен
источник
Я не мог с вами согласиться больше, и именно поэтому я спросил на этом форуме ... В конце концов, ответы должны быть где-то, не так ли? :)
Ловушка
1
Да. Ответ: «Это зависит».
user49117
6

Что касается «смущающе параллельных» проблем, то при использовании Intel TBB и OpenMP на C ++ я наблюдал примерно 10-кратное увеличение производительности по сравнению с аналогичными (чисто математическими) проблемами, которые были сделаны с C # и TPL. SIMD - это одна из областей, где C # не может конкурировать, но у меня также сложилось впечатление, что TPL имеет значительные накладные расходы.

Тем не менее, я использую C ++ только для задач, критичных к производительности, где я знаю, что смогу работать с многопоточностью и быстро получать результаты. Для всего остального C # (а иногда и F #) просто отлично.

Дмитрий Нестерук
источник
5

Это очень расплывчатый вопрос без реальных окончательных ответов.

Например; Я бы лучше играл в 3D-игры, созданные на C ++, чем на C #, потому что производительность, безусловно, намного лучше. (И я знаю XNA и т. Д., Но это совсем не похоже на реальную вещь).

С другой стороны, как упоминалось ранее; Вы должны развиваться на языке, который позволяет вам делать то, что вы хотите быстро, а затем при необходимости оптимизировать.

Дэвид Человек
источник
4
Не могли бы вы назвать несколько примеров? Игры, написанные на C #, что вы нашли медленным
Карл
1
Даже примеры приложений, которые пришли с установкой, были медленными.
Дэвид Человек
9
Сборщик мусора - огромная ответственность при создании игр на C #, так как он может вылететь в любой момент, вызывая большие паузы. Явное управление памятью облегчает разработку игр.
постфутурист
3
Большинство современных игр ограничены GPU. Для таких игр не имеет значения, если логика (исполняемая на процессоре) медленнее на 10%, они все еще ограничены GPU, а не CPU. Сборщик мусора является реальной проблемой, вызывая случайные короткие зависания, если распределение памяти не настроено должным образом.
Майкл Энтин
2
@postfuturist: Это не так на ПК; сборщик мусора делает такую ​​хорошую работу по входу и выходу, что у меня никогда не было проблем с этим. Однако на XBox 360 и Zune / Windows-7-Phone сборщик мусора далеко не такой умный, как на ПК; Я никогда не писал для них, но люди, которые сказали мне, что сборщик мусора - огромная проблема.
BlueRaja - Дэнни Пфлюгофт
5

Языки .NET могут быть такими же быстрыми, как код C ++, или даже быстрее, но код C ++ будет иметь более постоянную пропускную способность, поскольку среда выполнения .NET должна приостанавливаться для GC , даже если она очень умна в отношении своих пауз.

Поэтому, если у вас есть код, который должен постоянно работать быстро, без каких-либо пауз, в какой-то момент .NET будет вводить задержку , даже если вы очень осторожны с GC времени выполнения.

Флориан Дойон
источник
6
-1: это на самом деле миф. Во-первых, задержка идиоматического C ++ на самом деле ужасна и часто намного хуже, чем .NET, потому что RAII вызывает лавины деструкторов, когда большие структуры данных выпадают из области видимости, тогда как современные GC являются инкрементными, а .NET - даже параллельными. Во-вторых, вы можете полностью удалить GC-паузы в .NET, не выделяя их.
Джон Харроп
2
Если вы сделаете это, вам придется отказаться от использования BCL, так как большинство методов создают временные объекты.
Флориан Дойон
5
Это совершенно верно, только в .net 4 GC был сделан постепенно. У нас есть большое приложение на C #, которое останавливается на несколько секунд для GC. Для приложений, критичных к производительности, это убийца.
Джастин
5
Есть причина, почему программы, которые имеют тенденцию выдвигать аппаратные средства, склонны использовать C ++. У вас есть более точно настроенный контроль, когда вам это нужно. Производительность является ключевым фактором, когда вы нажимаете на систему, в противном случае используйте C # или Java, чтобы сэкономить ваше время.
ВоронойПотато
4
если вы не можете управлять поведением кэша, вы не можете победить оптимизированный код C ++. Отсутствие кэша от L1 до основной памяти может замедлить вашу работу в 100 раз.
DAG
4

Теоретически, для долго работающих приложений серверного типа JIT-скомпилированный язык может стать намного быстрее, чем нативно скомпилированный аналог. Поскольку JIT-скомпилированный язык обычно сначала компилируется на довольно низкоуровневый промежуточный язык, вы можете в любом случае выполнить многоуровневую оптимизацию прямо во время компиляции. Большое преимущество заключается в том, что JIT может продолжать перекомпилировать фрагменты кода на лету, поскольку он получает все больше и больше данных о том, как используется приложение. Он может организовать наиболее распространенные пути кода, чтобы предсказание ветвления могло выполняться как можно чаще. Он может переставлять отдельные блоки кода, которые часто вызываются вместе, чтобы держать их в кэше. Это может потратить больше усилий на оптимизацию внутренних циклов.

Я сомневаюсь, что это делается с помощью .NET или любого из JRE, но когда я учился в университете, его исследовали, поэтому не исключено, что подобные вещи могут в скором времени попасть в реальный мир. ,

Затмение
источник
4

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

Kalle
источник
4

Я тестировал vectorв C ++ и C # эквивалент - Listи простые 2d массивы.

Я использую версии Visual C # / C ++ 2010 Express. Оба проекта являются простыми консольными приложениями, я тестировал их в стандартном (без пользовательских настроек) режиме выпуска и отладки. Списки C # работают на моем компьютере быстрее, инициализация массива также быстрее в C #, математические операции выполняются медленнее.

Я использую Intel Core2Duo P8600 @ 2,4 ГГц, C # - .NET 4.0.

Я знаю, что реализация вектора отличается от C # list, но я просто хотел протестировать коллекции, которые я использовал бы для хранения своих объектов (и возможности использовать средство доступа к индексам).

Конечно, вам нужно очистить память (скажем, для каждого использования new), но я хотел сохранить код простым.

C ++ векторный тест :

static void TestVector()
{
    clock_t start,finish;
    start=clock();
    vector<vector<double>> myList=vector<vector<double>>();
    int i=0;
    for( i=0; i<500; i++)
    {
        myList.push_back(vector<double>());
        for(int j=0;j<50000;j++)
            myList[i].push_back(j+i);
    }
    finish=clock();
    cout<<(finish-start)<<endl;
    cout<<(double(finish - start)/CLOCKS_PER_SEC);
}

Список тестов C #:

private static void TestVector()
{

    DateTime t1 = System.DateTime.Now;
    List<List<double>> myList = new List<List<double>>();
    int i = 0;
    for (i = 0; i < 500; i++)
    {
        myList.Add(new List<double>());
        for (int j = 0; j < 50000; j++)
            myList[i].Add(j *i);
    }
    DateTime t2 = System.DateTime.Now;
    Console.WriteLine(t2 - t1);
}

C ++ - массив:

static void TestArray()
{
    cout << "Normal array test:" << endl;
    const int rows = 5000;
    const int columns = 9000;
    clock_t start, finish;

    start = clock();
    double** arr = new double*[rows];
    for (int i = 0; i < rows; i++)
        arr[i] = new double[columns];
    finish = clock();

    cout << (finish - start) << endl;

    start = clock();
    for (int i = 0; i < rows; i++)
        for (int j = 0; j < columns; j++)
            arr[i][j] = i * j;
    finish = clock();

    cout << (finish - start) << endl;
}

C # - массив:

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 * j;
    t2 = System.DateTime.Now;

    Console.WriteLine(t2 - t1);

}

Время: (выпуск / отладка)

C ++

  • Инициализация массива 600/606 мс,
  • Заполнение массива 200/270 мс,
  • 1сек / 13сек вектор инициализации и заполнения.

(Да, 13 секунд, у меня всегда есть проблемы со списками / векторами в режиме отладки.)

C #:

  • Инициализация массива 20/20 мс,
  • Заполнение массива 403/440 мс,
  • 710/742 мс Список инициализации и заполнения.
Wiory
источник
1
Я хотел бы видеть индекс доступа в std :: list. Во всяком случае, это занимает 37 секунд со списком, режим релиза. Выпуск без отладки: список 3 с, вектор 0,3 с. Возможно разыменование или что-то еще. Образец: nopaste.pl/12fb
Wiory
2
Для более точных измерений вы не должны использовать System.DateTime.Now, а, скорее, класс Секундомер .
Сэм
4
Одна из причин, по которой вы получаете такое медленное время заполнения для вектора в C ++, заключается в том, что вы используете push_back. На многих сообщениях это было показано медленнее, чем при использовании метода at или оператора []. Чтобы использовать любой из этих методов, вам нужно использовать метод изменения размера или резервирования. Кроме того, причина, по которой ваша инициализация занимает так много времени для случая вектора c ++, заключается в том, что вы заставляете оператор копирования или присваивания (не уверен, какой в ​​этом случае) инициализировать ваш вектор c ++. Для массива в c ++ есть алгоритм, который использует 2 новых вызова, а не 5001, и также ускоряет итерации.
Захария Крауса
5
Я думаю, что вы не сделали с ++ надлежащим образом. Просто взгляд и нашел так много вопросов. Например, vector <vector <double >> myList = vector <vector <double >> ()
DAG
2
Вот это да. Не уверен, какие выводы можно сделать из сравнения списков с массивами изменяемого размера, но если вы собираетесь использовать такие векторы, вам захочется узнать о Reserve (), мой друг, Reserve ().
U007D
3

Смотря как. Если байт-код транслируется в машинный код (а не только в JIT) (я имею в виду, если вы выполняете программу), и если ваша программа использует много распределений / освобождений, это может быть быстрее, потому что алгоритму GC просто нужен один проход (теоретически) через всю память один раз, но обычные вызовы malloc / realloc / free в C / C ++ вызывают издержки при каждом вызове (накладные расходы на вызов, издержки на структуру данных, пропадание кэша;)).

Так что это теоретически возможно (также для других языков GC).

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

Другим большим преимуществом является то, что SQL, как и «расширение» LINQ , предоставляет компилятору возможность оптимизировать обращения к базам данных (другими словами, компилятор может скомпилировать весь LINQ в один двоичный файл «blob», где вызываемые функции являются встроенными или для вашего использования оптимизирован, но я размышляю здесь).

Quonux
источник
1
Любой правильный разработчик C ++ не столкнется с проблемами, которые вы описываете. Только плохие программисты на Си, которые решили создавать классы для своих программ и называть это C ++, имеют такие проблемы.
уточнение
1
ради богов, это 8 лет, OMFGz
Quonux
не стесняйтесь давать лучший, более актуальный ответ
Quonux
2

Я предполагаю, что есть приложения, написанные на C #, работающие быстро, а также есть больше приложений, написанных на C ++, которые работают быстро (ну, C ++ просто старше ... и тоже принимают UNIX ...)
- вопрос действительно в том, что это за пользователи и разработчики жалуются на ...
Ну, ИМХО, в случае с C # у нас очень удобный интерфейс, очень хорошая иерархия библиотек и целая система интерфейса CLI. В случае C ++ у нас есть шаблоны, ATL, COM, MFC и целый набор уже написанного и запущенного кода, такого как OpenGL, DirectX и т. Д. ... Разработчики жалуются на неопределенно возросшие вызовы GC в случае C # (означает, что программа работает быстро, и в одну секунду - бац! он застрял).
Писать код на C # очень просто и быстро (не забывайте, что это также увеличивает вероятность ошибок. В случае C ++ разработчики жалуются на утечки памяти, - означает сбои, вызовы между DLL, а также на «DLL ад» - проблемы с поддержка и замена библиотек на более новые ...
Я думаю, чем больше у вас навыков в языке программирования, тем больше качества (и скорости) будет характеризовать ваше программное обеспечение.

bgee
источник
2

Я бы сказал так: программисты, которые пишут более быстрый код, являются более осведомленными о том, что заставляет современные машины работать быстрее, и, кстати, они также используют соответствующий инструмент, который обеспечивает точный низкоуровневый и детерминированный методы оптимизации. По этим причинам именно эти люди используют C / C ++, а не C #. Я бы сказал, что это факт.

Йохан Буле
источник
Minecraft с кодировкой Notch работает довольно быстро, учитывая количество данных, которыми он манипулирует. Кроме того, он закодировал это в основном в одиночку за сравнительно короткий промежуток времени, что было бы практически невозможно в C ++. Однако я согласен с методами оптимизации - если у вас есть дополнительное 10-кратное время разработки, чтобы ваш код выполнялся в два раза быстрее, это, вероятно, того стоит.
Билл К
2

Если я не ошибаюсь, шаблоны C # определяются во время выполнения. Это должно быть медленнее, чем шаблоны времени компиляции C ++.

И когда вы принимаете во внимание все другие оптимизации времени компиляции, упомянутые многими другими, а также отсутствие безопасности, которое действительно означает большую скорость ...

Я бы сказал, что C ++ - очевидный выбор с точки зрения скорости и минимального потребления памяти. Но это также приводит к большему времени на разработку кода и гарантирует, что вы не теряете память и не вызываете никаких исключений нулевого указателя.

Вердикт:

  • C #: более быстрое развитие, медленный запуск

  • C ++: медленная разработка, более быстрый запуск.

HumbleWebDev
источник
1

Это действительно зависит от того, чего вы пытаетесь достичь в своем коде. Я слышал, что это просто городская легенда, что есть разница в производительности между VB.NET, C # и управляемым C ++. Тем не менее, я обнаружил, по крайней мере в сравнении строк, что управляемый C ++ отбивает штаны из C #, что, в свою очередь, отбивает штаны из VB.NET.

Я ни в коем случае не делал исчерпывающих сравнений алгоритмической сложности между языками. Я также просто использую настройки по умолчанию на каждом из языков. В VB.NET я использую настройки, требующие объявления переменных и т. Д. Вот код, который я использую для управляемого C ++: (Как видите, этот код довольно прост). Я использую то же самое на других языках в Visual Studio 2013 с .NET 4.6.2.

#include "stdafx.h"

using namespace System;
using namespace System::Diagnostics;

bool EqualMe(String^ first, String^ second)
{
    return first->Equals(second);
}
int main(array<String ^> ^args)
{
    Stopwatch^ sw = gcnew Stopwatch();
    sw->Start();
    for (int i = 0; i < 100000; i++)
    {
        EqualMe(L"one", L"two");
    }
    sw->Stop();
    Console::WriteLine(sw->ElapsedTicks);
    return 0;
}
Чарльз Оуэн
источник
1

Есть некоторые серьезные различия между C # и C ++ в аспекте производительности:

  • C # основан на GC / куче. Выделение и сам GC являются накладными расходами как нелокальный доступ к памяти
  • Оптимизаторы C ++ стали очень хорошими за эти годы. JIT-компиляторы не могут достичь того же уровня, так как они имеют только ограниченное время компиляции и не видят глобальную область видимости

Кроме того, компетентность программиста играет также роль. Я видел плохой код C ++, где классы передавались по значению в качестве аргумента повсюду. На самом деле вы можете ухудшить производительность в C ++, если не знаете, что делаете.

gast128
источник
0

> Ведь ответы должны быть где-то, не так ли? :)

Ммм нет

Как отмечалось в нескольких ответах, вопрос недостаточно конкретизирован способами, которые вызывают вопросы в ответе, а не ответы. Взять только один путь:

А потом какие программы? Какая машина? Какая ОС? Какой набор данных?

Питер Мортенсен
источник
Я полностью согласен. Интересно, почему люди ожидают точного ответа (63,5%), когда задают общий вопрос. Я не думаю, что нет общего ответа на этот вопрос.
Зовите меня Стив
@callmesteve: Я знаю, что вы имеете в виду, но ваше последнее предложение должно звучать как гвозди на доске для любого программиста.
Wouter van Nifterick
1
Это, кажется, не отвечает на вопрос, и читается больше как комментарий или напыщенная речь.
Tas
-13

Вдохновленный этим, я провел быстрый тест с 60% общих инструкций, необходимых в большинстве программ.

Вот код C #:

for (int i=0; i<1000; i++)
{
    StreamReader str = new StreamReader("file.csv");
    StreamWriter stw = new StreamWriter("examp.csv");
    string strL = "";
    while((strL = str.ReadLine()) != null)
    {
        ArrayList al = new ArrayList();
        string[] strline = strL.Split(',');
        al.AddRange(strline);
        foreach(string str1 in strline)
        {
            stw.Write(str1 + ",");
        }
        stw.Write("\n");
    }
    str.Close();
    stw.Close();
}

Массив строк и arraylist используются специально для включения этих инструкций.

Вот код C ++:

for (int i = 0; i<1000; i++)
{
    std::fstream file("file.csv", ios::in);
    if (!file.is_open())
    {
        std::cout << "File not found!\n";
        return 1;
    }

    ofstream myfile;
    myfile.open ("example.txt");
    std::string csvLine;

    while (std::getline(file, csvLine))
    {
        std::istringstream csvStream(csvLine);
        std::vector csvColumn;
        std::string csvElement;

        while( std::getline(csvStream, csvElement, ‘,’) )
        {
            csvColumn.push_back(csvElement);
        }

        for (std::vector::iterator j = csvColumn.begin(); j != csvColumn.end(); ++j)
        {
            myfile << *j << ", ";
        }

        csvColumn.clear();
        csvElement.clear();
        csvLine.clear();
        myfile << "\n";
    }
    myfile.close();
    file.close();
}

Размер входного файла, который я использовал, составлял 40 КБ.

И вот результат -

  • Код C ++ работал за 9 секунд.
  • Код C #: 4 секунды !!!

О, но это было на Linux ... С C # работает на Mono ... И C ++ с g ++.

Хорошо, это то, что я получил в Windows - Visual Studio 2003 :

  • Код C # работал за 9 секунд.
  • C ++ код - ужасные 370 секунд !!!
RKS
источник
7
Вы используете разные структуры данных и библиотечный код, хотя «370 секунд» действительно указывает на что-то ужасное - вы случайно не запускаете это в отладчике? Я подозреваю, что производительность используемой вами библиотеки CSV более интересна, чем производительность используемого вами языка. Я бы поставил под сомнение использование вектора в этом контексте и какие оптимизации вы использовали. Кроме того, широко известно, что iostreams (в частности, «myfile << * j <<», «;») намного медленнее, чем другие методы записи в файл, по крайней мере для некоторых распространенных реализаций.
Арафангион
6
Наконец, вы делаете больше работы в версии C ++. (Почему вы очищаете csvColumn, csvElement и csvLines?)
Арафангион
2
Каждая итерация цикла while будет разрушать и восстанавливать std :: istream, std :: vector и std :: string. В то время как тело while выходит из области видимости при каждой итерации, все эти переменные в области видимости будут разрушаться и создаваться на каждой итерации.
doug65536
1
Судя по чтению вашего кода C ++, вы пытаетесь скопировать из одного файла в другой файл. Вместо использования сложных взаимодействий между файловыми потоками, строками, векторами и строковыми потоками, вы могли бы просто скопировать поток входных файлов в поток выходных файлов. Это сэкономило бы много времени и памяти.
Захария Крауса
2
чтобы делать тесты скорости, проверяйте вещи в памяти, не попадайте на дисковый ввод-вывод, если только вы не тестировали новейшие твердотельные накопители и не предназначались для вашего приложения производительности. Поскольку компьютеры постоянно пишут на диск, даже если вы не касаетесь клавиатуры.
user3800527