2011-10-19 42 views
3

简单地创建一个真正的巨大的源文件,手动初始化一个具有数十万个值的向量的合法优化吗?而不是将具有相同值的文本文件解析为矢量?巨大的.cpp文件比从文本文件中读取更好?

对不起,可能措辞更好。解析文本文件的功能非常缓慢,因为C++的流读取速度非常慢(大约需要6分钟,而不是C#版本中的大约6秒。)

会使得海量数组初始化文件成为合法的解决方案吗?这似乎并不优雅,但如果它的速度更快,那么我想这是最好

这是文件的阅读代码:从文本文件

//parses the text path vector into the engine 
    void Level::PopulatePathVectors(string pathTable) 
    { 
     // Read the file line by line. 
     ifstream myFile(pathTable); 

      for (unsigned int i = 0; i < nodes.size(); i++) 
      { 
       pathLookupVectors.push_back(vector<vector<int>>()); 

       for (unsigned int j = 0; j < nodes.size(); j++) 
       { 
        string line; 

        if (getline(myFile, line)) //enter if a line is read successfully 
        { 
         stringstream ss(line); 
         istream_iterator<int> begin(ss), end; 
         pathLookupVectors[i].push_back(vector<int>(begin, end)); 
        } 
       } 
      } 
     myFile.close(); 
    } 

样品线(其中有大约50万具有类似格式但长度不同的线条

0 5 3 12 65 87 n 
+0

问题不在于C++,它是您读取数据和初始化向量的函数。 – onit

+4

@bzlm哇谢谢!学会编码,呵呵,从来没有想过那个。屁股。 http://stackoverflow.com/questions/7809473/why-is-this-so-much-slower-in-c – SirYakalot

+1

这可能是合法的,取决于你的用例,但它也脆弱,除非你只关心工作那一个数据集。但是,您可以向我们展示您的文件阅读代码,也许有一些问题需要解决。 – birryree

回答

3

6分钟vs 6秒!!一定是你的C++代码有问题。在您恢复到您的帖子中提到的极端“优化”之前,使用优秀的旧方法对其进行优化。

也知道从文件中读取将允许您在不更改源代码的情况下更改矢量内容。如果你按照你提到的方式来做,你将不得不重新编码,重新编译链接。

2

取决于数据是否更改。如果数据可以/需要更改(编译后),则唯一的选择是从文本文件加载它。如果没有,那么我认为没有任何损害来编译它。

+1

...如果数据在编译时间^之后改变^。 –

+0

所以它不会被认为是不好的做法?我想这会快很多..还是会呢? – SirYakalot

+1

这样做可以帮助您验证有关C++中IO速度慢的假设。但是很可能代码中的一个大问题与向量重新分配有关。 (使用reserve()成员函数来解决这个问题。) – jszpilewski

-3

不要使用标准输入流,它非常慢。 有更好的选择。

由于人们决定,因为他们懒得使用谷歌,在这里downvote我的回答:

http://accu.org/index.php/journals/1539

+1

我个人不知道C++输入流的性能,但即使它不好,您也需要指定可用的替代方法。 –

+0

本网站上的用户是否无法使用谷歌?或者是stackoverflow自己的搜索?在stackoverflow上已经有很多像这样的问题,他们都建议您使用另一个io解决方案。只需运行自己的测试,就像C++的流vs c的流,我敢打赌,需要10分钟的C++需要20秒我c。我的回答是他的问题的完美解决方案。 –

+0

对于输出而言太糟糕了,而不是输入... –

4

首先,确保你提供最高级别的优化编译,那么请加入按照下面标记的行,然后再次测试。我怀疑这会解决问题,但它可能有帮助。很难说,直到我看到结果。

//parses the text path vector into the engine 
void Level::PopulatePathVectors(string pathTable) 
{ 
    // Read the file line by line. 
    ifstream myFile(pathTable); 

    pathLookupVectors.reserve(nodes.size()); // HERE 
    for (unsigned int i = 0; i < nodes.size(); i++) 
    { 
     pathLookupVectors.push_back(vector<vector<int> >(nodes.size())); 
     pathLookupVectors[i].reserve(nodes.size()); // HERE 

     for (unsigned int j = 0; j < nodes.size(); j++) 
     { 
      string line; 

      if (getline(myFile, line)) //enter if a line is read successfully 
      { 
       stringstream ss(line); 
       istream_iterator<int> begin(ss), end; 
       pathLookupVectors[i].push_back(vector<int>(begin, end)); 
      } 
     } 
    } 
    myFile.close(); 
} 
+0

我可以证实这是非常好的建议。 –

+1

当你在它的时候,你也可能把'string line;'移出循环。 - 但是再次,很难相信这些东西会让程序加载文件的速度提高5分54秒(对于我的测试文件为490000行数字的C++ 11实现G ++库,保留实际上没有影响)。 – UncleBens

+1

将'stringstream ss(line);'移出循环并用'ss.clear()替换它,我也看到显着的改善(> 25%); ss.str(line);' – UncleBens

0

我不会考虑将静态数据编译到您的应用程序中是不好的做法。如果在没有重新编译的情况下几乎不需要更改数据,那么在编译时解析文件不仅会提高运行时性能(因为数据已由编译器预先解析并且在运行时处于可用格式),而且还会减少风险(如在运行时没有找到数据文件或任何其他解析错误)。

确保用户不需要改变数据(或者有办法重新编译程序),记录你的动机,你应该绝对没问题。

也就是说,如果需要,你可以使iostream版本更快。

0

在C++文件中使用巨大的数组是一个完全允许的选项,具体取决于大小写。

您必须考虑数据是否会发生变化以及发生频率。

如果你把它放在一个C++文件中,这意味着你每次数据改变时都必须重新编译你的程序(并且每次将它分发给你的客户!)所以如果你这样做不是一个好的解决方案必须将该程序分发给其他人。

现在,如果每个数据更改都允许编译,那么您可以拥有两个最好的世界:只需使用一个小脚本(例如在python或perl中),它将采用.txt并生成一个C++文件,所以文件解析只需要对每次数据更改进行一次。您甚至可以将此步骤与自动依赖关系管理一起集成到构建过程中。

祝你好运!

1

我能够与Boost.Spirit 2.5以获得以下结果:

$ time ./test input 

real 0m6.759s 
user 0m6.670s 
sys  0m0.090s 

“输入”是包含含有0 65535每个之间和10个的随机整数500000行的文件。

下面的代码:

#include <vector> 

#include <boost/spirit/include/qi.hpp> 
#include <boost/spirit/include/classic_file_iterator.hpp> 

using namespace std; 
namespace spirit = boost::spirit; 
namespace qi = boost::spirit::qi; 
namespace ascii = boost::spirit::ascii; 

typedef vector<int> ragged_matrix_row_type; 
typedef vector<ragged_matrix_row_type> ragged_matrix_type; 


template <class Iterator> 
struct ragged_matrix_grammar : qi::grammar<Iterator, ragged_matrix_type()> { 

    ragged_matrix_grammar() : ragged_matrix_grammar::base_type(ragged_matrix_) { 

    ragged_matrix_ %= ragged_matrix_row_ % qi::eol; 
    ragged_matrix_row_ %= qi::int_ % ascii::space; 

    } 

    qi::rule<Iterator, ragged_matrix_type()> ragged_matrix_; 
    qi::rule<Iterator, ragged_matrix_row_type()> ragged_matrix_row_; 

}; 

int main(int argc, char** argv){ 

    typedef spirit::classic::file_iterator<> ragged_matrix_file_iterator; 

    ragged_matrix_type result; 
    ragged_matrix_grammar<ragged_matrix_file_iterator> my_grammar; 
    ragged_matrix_file_iterator input_it(argv[1]); 

    qi::parse(input_it, input_it.make_end(), my_grammar, result); 

    return 0; 

} 

在这一点上,result包含了衣衫褴褛的矩阵,可通过打印的内容进行确认。在我的情况下,“粗糙的矩阵”不是很粗糙 - 它是一个500000 x 10的矩形 - 但它并不重要,因为我非常肯定语法是正确的。当我在解析(〜4秒)之前将整个文件读入内存时,我得到了更好的结果,但代码更长,并且通常不希望将大文件全部复制到内存中。

注:我的测试机器有一个SSD,所以我不知道你是否会得到和我一样的数字(除非你的测试机器也有SSD)。

HTH!