简单地创建一个真正巨大的源文件是一个合理的优化,它可以手动初始化具有数十万个值的向量?而不是将具有相同值的文本文件解析为向量?
抱歉,措辞可能更好。解析文本文件的函数非常慢,因为C ++的流读取非常慢(在C#版本中大约需要6分钟而不是大约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();
}
来自文本文件的示例行(其中有大约五十万行相似的格式,但长度各不相同。
0 5 3 12 65 87 n
答案 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();
}
答案 1 :(得分:3)
6分钟vs 6秒!!你的C ++代码必定有问题。在您恢复到帖子中提到的极端“优化”之前,请使用旧的方法对其进行优化。
还要知道从文件读取将允许您更改矢量内容而不更改源代码。如果按照你提到的方式进行,你将不得不重新编码,重新编译n链接。
答案 2 :(得分:2)
取决于数据是否发生变化。如果数据可以/需要更改(在编译时间之后),那么唯一的选择就是从textfile加载它。如果没有,我认为编译它没有任何伤害。
答案 3 :(得分:1)
我能用Boost.Spirit 2.5得到以下结果:
$ time ./test input
real 0m6.759s
user 0m6.670s
sys 0m0.090s
'input'是一个包含500,000行的文件,包含10个随机整数,每个整数在0到65535之间。
以下是代码:
#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!
答案 4 :(得分:0)
我不会考虑将静态数据编译到您的应用程序中是不好的做法。如果在没有重新编译的情况下几乎不可能需要更改数据,那么在编译时解析文件不仅可以提高运行时性能(因为您的数据已经由编译器预解析并且在运行时以可用格式提供),而且还减少了风险(如在运行时未找到数据文件或任何其他解析错误)。
确保用户无需更改数据(或有办法重新编译程序),记录您的动机,您应该绝对没问题。
也就是说,如果有必要,你可以让iostream版本更快。
答案 5 :(得分:0)
在C ++文件中使用大型数组是一个完全允许的选项,具体取决于具体情况。
您必须考虑数据是否会发生变化以及发生频率。
如果你把它放在一个C ++文件中,这意味着你必须在每次数据更改时重新编译你的程序(并且每次都将它分发给你的客户!)所以如果你有这个,这将不是一个好的解决方案将程序分发给其他人。
现在,如果每次数据更改都允许编译,那么您可以充分利用两个世界:只需使用一个小脚本(例如在python或perl中),它将获取.txt并生成C ++文件,因此每次数据更改只需要进行一次文件解析。您甚至可以使用自动依赖关系管理将此步骤集成到构建过程中。
祝你好运!答案 6 :(得分:-3)