Почему Java читает большой файл быстрее, чем C++?
у меня есть файл 2 ГБ (iputfile.txt), в котором каждая строка в файле есть слова, как:
apple
red
beautiful
smell
spark
input
мне нужно написать программу, чтобы прочитать каждое слово в файле и печатать количество слов. Я написал его с помощью Java и C++, но результат удивителен: Java работает в 2,3 раза быстрее, чем C++. Мой код выглядит следующим образом:
C++:
int main() {
struct timespec ts, te;
double cost;
clock_gettime(CLOCK_REALTIME, &ts);
ifstream fin("inputfile.txt");
string word;
int count = 0;
while(fin >> word) {
count++;
}
cout << count << endl;
clock_gettime(CLOCK_REALTIME, &te);
cost = te.tv_sec - ts.tv_sec + (double)(te.tv_nsec-ts.tv_nsec)/NANO;
printf("Run time: %-15.10f sn", cost);
return 0;
}
выход:
5e+08
Run time: 69.311 s
Java:
public static void main(String[] args) throws Exception {
long startTime = System.currentTimeMillis();
FileReader reader = new FileReader("inputfile.txt");
BufferedReader br = new BufferedReader(reader);
String str = null;
int count = 0;
while((str = br.readLine()) != null) {
count++;
}
System.out.println(count);
long endTime = System.currentTimeMillis();
System.out.println("Run time : " + (endTime - startTime)/1000 + "s");
}
выход:
5.0E8
Run time: 29 s
почему Java быстрее чем C++ в этой ситуации и как я могу улучшить производительность c++?
5 ответов:
вы не сравниваете одно и то же. Программа Java читает строки, опускаясь на новую строку, в то время как программа C++ читает пробелы, разделенные "словами", что является немного дополнительной работой.
попробовать
istream::getline.позже
вы также можете попробовать выполнить элементарную операцию чтения, чтобы прочитать массив байтов и проверить его на наличие новых строк.
даже позднее
на моем старом ноутбуке Linux, jdk1. 7. 0_21 и не говорите мне, что это старый 4.3.3 занимает примерно столько же времени, по сравнению с C++ getline. (Мы установили, что чтение слов происходит медленнее.) Нет большой разницы между-O0 и-O2, что меня не удивляет, учитывая простоту кода в цикле.
последнее замечание Как я и предлагал, фин.чтение (buffer, LEN) с LEN = 1MB и использование memchr для сканирования "\n " приводит к еще одному улучшению скорости примерно на 20%, что делает C (сейчас нет никакого C++) быстрее, чем Ява.
есть ряд существенных различий в том, как языки обрабатывают I / O, все из которых могут иметь значение, в одну сторону или еще один.
пожалуй, первый (и самый важный) вопрос: как данные, закодированные в текстовом файле. Если это однобайтовые символы (ISO 8859-1 или UTF-8), то Java должен преобразовать его в UTF-16 перед обработкой; в зависимости от локали, C++ может (или может не) также конвертировать или сделать некоторые дополнительные проверки.
как было указано (частично, по крайней мере), в C++,
>>использует специфический языкisspace,getlineпросто сравните'\n', который, вероятно, быстрее. (Типичные реализацииisspaceбудет использовать растровое изображение, что означает дополнительную память доступ для каждого персонажа.)уровни оптимизации и конкретные реализации библиотеки могут также варьироваться. Это не редкость в C++ для одной библиотеки реализация быть в 2 или 3 раза быстрее другого.
наконец, самое существенное различие: C++ различает между текстовыми и двоичными файлами. Вы открыли файл в текстовом режиме; это означает, что он будет "предварительно" в самый низкий уровень, прежде чем даже операторы извлечения увидят его. Этот зависит от платформы: для платформ Unix "обработка" нет; на Windows, она преобразует пар переводы строк в
'\n', который будет иметь определенное влияние на производительность. если я отзыв правильно (я не использовал Java в течение нескольких лет), Java ожидает функции более высокого уровня для обработки этого, поэтому такие функции, какreadLineбудет немного сложнее. Просто предполагаю вот, но я подозреваю, что дополнительная логика у высшего уровень стоит меньше во время выполнения, чем предварительная обработка буфера на уровне нижний уровень. (Если вы тестируете под Windows, вы можете поэкспериментируйте с открытием файла в двоичном режиме на C++. Этот не должно иметь никакого значения в поведении программы, когда вы используете>>; любой дополнительный CR будет считаться пробелом. Сgetline, вам придется добавить логику, чтобы удалить любой трейлинг'\r'в ваш код.)
Я бы заподозрил, что главное отличие в том, что
java.io.BufferedReaderработает лучше, чемstd::ifstreamпотому что он буферизует, а ifsteam-нет. BufferedReader читает большие куски файла заранее и передает их в вашу программу из ОЗУ при вызовеreadLine(), в то время как std::ifstream читает только несколько байтов за раз, когда вы предлагаете ему вызвать>>-оператора.последовательный доступ к большим объемам данных с жесткого диска, как правило, намного быстрее, чем доступ ко многим небольшим кускам по одному.
более справедливым сравнением было бы сравнить std:: ifstream с unbuffered java. io. FileReader.
Я не эксперт в C++, но у вас есть по крайней мере следующее, чтобы повлиять на производительность:
- кэширование уровня ОС для файла
- для Java вы используете буферизованное средство чтения, а размер буфера по умолчанию равен странице или чему-то еще. Я не уверен, как потоки C++ делают это.
- поскольку файл настолько велик, что JIT, вероятно, будет запущен, и он, вероятно, компилирует байтовый код Java лучше, чем если бы вы не включали оптимизацию для своего C++ компилятор.
с I / O стоимость является основной стоимостью здесь, я думаю, 1 и 2 являются основными причинами.
Я бы также попытался использовать mmap вместо стандартного чтения/записи файла. Это должно позволить вашей ОС обрабатывать чтение и запись, в то время как ваше приложение связано только с данными.
нет ситуации, когда C++ не может быть быстрее Java, но иногда это требует много работы от очень талантливых людей. Но я не думаю, что это должно быть слишком трудно победить, так как это простая задача.
mmap для Windows описывается в Отображение ( MSDN).
Comments