为什么我的C ++文本文件解析脚本比我的Python脚本慢得多?

时间:2015-05-12 16:55:02

标签: python c++

我目前正在尝试自学c ++,而我正在研究文件IO。我已经阅读了cplusplus.com教程,并使用了我在那里学到的基本文件IO技术:

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 MB的文件。以下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")

唯一值得注意的区别是我使用内置的strip()函数去除换行而不是使用正则表达式。 (这是我非常慢的执行时间的来源吗?)

我不确定程序中可怕的低效率来自哪里。一个10MB的文件不应该花这么长时间来解析!

*编辑:最初显示文件为20MB,只有10MB。

根据Nathan Oliver的建议,我使用了以下代码,仍然需要大约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&gt;&gt;读数在每个空白字符处停止?不知道它是如何工作的,但它为文件中的每个数字运行while循环的迭代,而不是文件中的每一行。

1 个答案:

答案 0 :(得分:5)

你所拥有的代码较慢,因为你在C ++代码中进行了两次正则表达式调用。只是因为你知道你是否使用>>运算符来读取文件,它将忽略前导空格并读取直到找到另一个空白字符。你可以轻松地编写你的函数:

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

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