2015-05-12 2 views
2

В настоящее время я пытаюсь научить себя C++, и я работаю над файлом IO. Я прочитал через cplusplus.com учебник, и я использую основные методы файла ввода-вывода, я узнал, что:Почему мой сценарий синтаксического анализа текстового файла на C++ намного медленнее, чем мой скрипт Python?

std::ifstream \\using this to open a read-only file 
std::ofstream \\using this to create an output file 
std::getline \\using this to read each line of the file 
outputfile << linecontents \\using this to write to the output file 

У меня есть примерно 10MB текстовый файл, содержащий первый миллион простых чисел, разделенных пробелами, 8 простых чисел к линии. Моя цель - написать программу, которая откроет файл, прочитает содержимое и напишет новый файл с одним простым числом на строку. Я использую регулярные выражения, чтобы разбить пробелы на концах каждой строки и заменить пробел между каждым числом одним символом новой строки.

Базовый алгоритм прост: используя регулярные выражения, я обрезаю пробелы в концах каждой строки и заменяю пробел посередине символом новой строки и записываю эту строку в выходной файл. Я написал «тот же самый» алгоритм в C++ и Python (за исключением того, что я использую встроенную функцию strip() для удаления начального и конечного пробелов), а программа Python намного быстрее! Я ожидаю обратное; Я думаю, что (хорошо написанная) программа на C++ должна быть молниеносной, а программа Python в 10-20 раз медленнее. Независимо от того, какая оптимизация выполняется за кадром в Python, хотя она делает это быстрее, чем моя «эквивалентная» программа на C++.

Мои регулярные выражения поиски:

std::tr1::regex rxLeadingTrailingWS("^(\\s)+|(\\s)+$"); //whitespace at beginning or end of string 
std::tr1::regex rxWS("(\\s)+"); //whitespace anywhere 

Мой файл разбора кода:

void ReWritePrimesFile() 
{ 
    std::ifstream readFile("..//primes1.txt"); 
    std::ofstream reducedPrimeList("..//newprimelist.txt"); 
    std::string readout; 
    std::string tempLine; 

    std::tr1::regex rxLeadingTrailingWS("^(\\s)+|(\\s)+$"); //whitespace at beginning or end of string 
    std::tr1::regex rxWS("(\\s)+"); //whitespace anywhere 
    std::tr1::cmatch res; //the variable which a regex_search writes its results to 

    while (std::getline(readFile, readout)){ 
     tempLine = std::tr1::regex_replace(readout.c_str(), rxLeadingTrailingWS, ""); //remove leading and trailing whitespace 
     reducedPrimeList << std::tr1::regex_replace(tempLine.c_str(), rxWS, "\n") << "\n"; //replace all other whitespace with newlines 
    } 

    reducedPrimeList.close(); 
} 

Однако этот код занимает минут, чтобы разобрать через 10 Мб файла с. Следующий сценарий Python занимает около 1-3 секунд (не засек):

import re 
rxWS = r'\s+' 
with open('pythonprimeoutput.txt', 'w') as newfile: 
    with open('primes1.txt', 'r') as f: 
     for line in f.readlines(): 
      newfile.write(re.sub(rxWS, "\n", line.strip()) + "\n") 

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

Я совсем не уверен, откуда исходит ужасная неэффективность моей программы. Файл 10 Мбайт не должен длиться так долго!

* отредактировано: изначально был показан файл размером 20 МБ, это всего лишь 10 МБ.

По предложению Натана Оливера я использовал следующий код, который по-прежнему занимал около 5 минут. Теперь это почти тот же алгоритм, который я использовал в Python. Все еще не уверен, что другое.

void ReWritePrimesFile() 
{ 
    std::ifstream readFile("..//primes.txt"); 
    std::ofstream reducedPrimeList("..//newprimelist.txt"); 
    std::string readout; 
    std::string tempLine; 

    //std::tr1::regex rxLeadingTrailingWS("^(\\s)+|(\\s)+$"); //whitespace at beginning or end of string 
    std::tr1::regex rxWS("(\\s)+"); //whitespace anywhere 
    std::tr1::cmatch res; //the variable which a regex_search writes its results to 

    while (readFile >> readout){ 
     reducedPrimeList << std::tr1::regex_replace(readout.c_str(), rxWS, "\n") + "\n"; //replace all whitespace with newlines 
    } 

    reducedPrimeList.close(); 
} 

второе редактирование: мне пришлось добавить дополнительный символ новой строки в конце строки regex_replace. По-видимому, чтение readFile >> останавливается на каждом символе пробела? Не знаете, как это работает, но он выполняет итерацию цикла while для каждого числа в файле, а не для каждой строки в файле.

+3

Сравнение несправедливо. Вы используете регулярное выражение на C++ дважды, а само регулярное выражение на C++ более сложное, чем python. – deepmax

+2

Более близкий эквивалент C++ к строке.strip() 'будет' boost :: trim (line) '. –

+0

Несколько минут все еще кажется действительно высоким. Попробуйте повторить второе регулярное выражение и время снова, за точку @ deepmax. Мне интересно, есть ли разница в том, как происходит процесс ввода-вывода файлов. Однако, чтобы удалить мой первоначальный ответ, так как неправильно было слишком быстро прочитывать вопрос. Сожалею! –

ответ

5

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

void ReWritePrimesFile() 
{ 
    std::ifstream readFile("..//primes1.txt"); 
    std::ofstream reducedPrimeList("..//newprimelist.txt"); 
    std::string readout; 

    while(readFile >> readout) 
     reducedPrimeList << readout << '\n'; 
} 
+0

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

+1

Код @JackGeiger действительно не должен быть добавлен к комментариям. Были ли у вас какие-либо тайминги, чтобы сравнить, сколько времени занимает каждый другой подход? Как сказал Павел выше, какие-либо оптимизации включены/как вы компилируете код? – NathanOliver

+1

@JackGeiger: Есть два узких места для ввода/вывода: 1) получение данных и 2) преобразование из текстового представления во внутреннее представление. Найдите в Интернете «stackoverflow C++ optimize read file». –

Смежные вопросы