C ++ намного быстрее, чем запись сценария Bash в текстовый файл

17

Я хотел протестировать производительность записи в файл в скрипте bash по сравнению с программой на C ++.

Вот сценарий bash:

#!/bin/bash

while true; do
        echo "something" >> bash.txt
done

Это добавило около 2-3 КБ к текстовому файлу в секунду.

Вот код C ++:

#include <iostream>
#include <fstream>

using namespace std;

int main() {
    ofstream myfile;
    myfile.open("cpp.txt");

    while (true) {
        myfile << "Writing this to a file Writing this to a file \n";
    }

    myfile.close();
}

Это создало текстовый файл размером ~ 6 ГБ менее чем за 10 секунд.

Что делает этот код на C ++ намного быстрее и / или этот скрипт bash настолько медленнее?

    
задан obl 04.07.2017 в 20:31
источник
  • Просто угадайте здесь, но я бы сказал, что основное отличие состоит в том, что пакет открывается и закрывает файл каждой итерацией, а C ++ - нет. Попробуйте переместить open () и close () внутри цикла на C ++, чтобы иметь справедливое сравнение производительности (вам нужно передать ios :: app для открытия) –  IlBeldus 04.07.2017 в 20:34
  • Или, переместите перенаправление в цикле в сценарии оболочки: while true; делать ...; done >> bash.txt. –  chepner 04.07.2017 в 20:35
  • Подтверждено использование strace, которое мой bash открывает и закрывает файл bash.txt каждый раз. –  aschepler 04.07.2017 в 20:40
  • @obl Это связано с вашим вопросом в том, что это комментарий о избыточности ненужного кода в нем. Если вам не платят строки кода, вы можете считать это полезной информацией, знаниями, которые могут помочь вам написать более сжатый код в будущем. –  juanchopanza 04.07.2017 в 20:42
  • Посмотрите, как сравнивается такая глупая небольшая программа: #include <fstream> int main () {while (true) {std :: ofstream myfile ("cpp.txt", std :: ios :: app); myfile << "Запись этого файла в файл Запись этого файла в \ n"; }} –  user4581301 04.07.2017 в 20:51
Показать остальные комментарии

3 ответа

38

Есть несколько причин.

Во-первых, интерпретируемые среды исполнения (например, bash , perl наряду с не-JITed lua и python и т. д.), как правило, намного медленнее, чем даже плохо написанные скомпилированные программы ( C , C++ и т. д.).

Во-вторых, обратите внимание, как фрагментированный ваш код bash - он просто записывает строку в файл, затем записывает еще одну и так далее. Ваша программа на C ++, с другой стороны, выполняет буферизированную запись - даже без ваших прямых усилий. Вы можете увидеть, как будет работать медленнее, если вы замените

myfile << "Writing this to a file Writing this to a file \n";

с

myfile << "Writing this to a file Writing this to a file" << endl;

для получения дополнительной информации о том, как потоки реализованы на C ++ и почему \n отличается от endl , см. любую справочную документацию на C ++.

В-третьих, как показывают комментарии, ваш скрипт bash выполняет открытие / закрытие целевого файла для каждой строки. Это подразумевает значительные накладные расходы по производительности - представьте, что myfile.open и myfile.close перемещены внутри вашего тела цикла!

    
ответ дан iehrlich 04.07.2017 в 20:37
  • Промывка производительности вниз по стоку - отличное начало. Следующий шаг - открыть файл для добавления и закрытия в каждом цикле. Должно быть еще ближе. –  user4581301 04.07.2017 в 20:42
  • @ user4581301 да, я хоть об этом (см. править), но был не совсем уверен - не эксперт в bash :) –  iehrlich 04.07.2017 в 20:43
  • IIRC, строки bash должны быть переведены / «построены» на native каждый раз. Это не относится к perl, который компилируется только один раз или python, который скомпилирован в байтовый код. Bash не будет строить линию до тех пор, пока она не запустит ее, а perl построит все в начале и т. Д. –  ray 04.07.2017 в 21:05
  • Запуск его с помощью 'endl' вместо '\ n' сделал его значительно медленнее, но все же быстрее, чем скрипт bash. Выполняя код, отправленный @ user4581301, производительность была очень похожа на производительность скрипта bash. –  obl 04.07.2017 в 21:45
  • «... интерпретируемые среды выполнения (например, ... python ...»). Это хотя? CPython, реализация Python по умолчанию, компилирует исходный код Python в байт-код, который запускается на виртуальной машине (которую некоторые называют интерпретатор, и это делает вещи еще более запутанными). Я не знаком с Perl, но я не был бы удивлен, если бы он использовал аналогичную конструкцию. Я думаю, что чисто интерпретированные языковые реализации в наши дни довольно редки. конечно Unix shells все еще есть. –  marcelm 05.07.2017 в 00:49
Показать остальные комментарии
6

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

MSG="something"
logfile="test.txt"
(
for i in {1..10000}; do
        echo $MSG
done
) >> $logfile

Что будет писать сообщение 10k раз, но только один раз открыть журнал.

    
ответ дан Elliott Frisch 05.07.2017 в 05:33
  • эхо - это bash builtin –  Basile Starynkevitch 05.07.2017 в 05:37
  • @BasileStarynkevitch Достаточно честный. Уже поздно здесь. И это было действительно тангенциально, поэтому я удалил его. –  Elliott Frisch 05.07.2017 в 05:43
-3

Скомпилированные или интерпретируемые языки

Bash интерпретируется при компиляции C ++. Просто это делает его намного быстрее

    
ответ дан Reece Ward 04.07.2017 в 20:36
  • Иногда. И иногда интерпретируемый язык имеет изящные маленькие инструкции, настолько плотно оптимизированные, что они вызывают ожидания прямо из воды. –  user4581301 04.07.2017 в 20:38
  • @ user4581301 Ну, технически они не интерпретируются на данный момент, но JIT / AOT-compiled;) –  iehrlich 04.07.2017 в 20:44
  • Нет ... Баш интерпретируется, и да, они могут быть быстрыми, но вы все еще должны понимать, что это всегда будет несколько медленнее. Вы можете скомпилировать его, но это не то, о чем мы говорим –  Reece Ward 04.07.2017 в 20:47
  • @iehrlich, даже не дразня, вы иногда сталкиваетесь с «Святым Smurf!». Хорошим примером является старый матлаб. Сценарий медленный, но код, поддерживающий скрипт, имеет серьезный импульс на этом этапе. –  user4581301 04.07.2017 в 20:48
  • Интерпретированный / JIT / скомпилированный не является особенно актуальным в этом случае, поскольку ввод-вывод является узким местом. Использование ЦП будет находиться ниже 1% в течение всей продолжительности программы, поэтому не имеет значения, что версия C ++ быстрее во время этого 1%. Ответ эхрлиха прав; проблема заключается в том, что скрипт bash открывает файл заново каждый раз, когда он печатает строку, в то время как версия C ++ держит ее открытой, пока она не будет выполнена. –  Ray 05.07.2017 в 01:05