我有一个大约400MB的1000行文件,该文件代表一些表示为字符串的数字数据。 我想转置数据以便每行只有1000个字符串,(以便我可以打开它并用pandas快速绘制)。
我将整个文件导入到要转置的字符串向量中(最终想写回文件)。
我使用两个嵌套循环来遍历2d结构,并将其写入一些std :: ofstream中。很长 然后,我尝试着眼于移调,并编写了以下代码:
//Read 400MB file, 90K strings per line and 1K lines, and store it into
std::vector<std::vector<std::string>> mData;
// ...
// IO the file and populate mData with raw data
// ...
//All rows have same number of string
size_t nbRows = mData.size();
size_t nbCols = mData[0].size();
std::vector<std::vector<std::string> > transposedData(nbCols);
for(size_t i = 0 ; i < nbCols ; ++i)
{
transposedData[i].resize(nbRows);
for(size_t j = 0 ; j < nbRows ; ++j)
{
transposedData[i][j] = doc.mData[j][i];
}
}
我认为几秒钟就足够了,但是要花几分钟。 另外,我尝试使用不同的输入尺寸(对于3MB的文件,每行只有更多的字符串,对于400MB的相同文件大小),并且输入速度要快得多。
编辑1
根据人们的建议,我使用callgrind进行了性能分析。 在此过程中,我收到了以下消息: ...线程1中的brk段溢出:无法增长到...
我分析了结果并在这里总结:
25%花费在basic_string的operator =中
21%的成本用于basic_string的构造(新时间只有3%)
外部向量在operator()[]中花费了14%
内部向量
谢谢您的建议。
答案 0 :(得分:1)
首先,在对一段代码缓慢的原因进行任何声明之前,您应该真正在计算机上测量其性能,然后通过手头的数据推断出为什么。
这表示我对此很有信心,因为问题可能出在以下事实:您正在分配90k
个字符串向量,每个向量的大小为1k
。如您所知,内存分配是昂贵的,它可能可以解释您的性能损失。
以下是仅使用预先分配的1D
数组来实现代码的方法。
size_t nbRows = mData.size();
size_t nbCols = mData[0].size();
auto get_idx = [](const int i, const int nr, const int j)
{
return i*nr+j;
};
std::vector<std::string> transposedData(nbCols*nbRows);
for(size_t i = 0 ; i < nbCols ; ++i)
{
for(size_t j = 0 ; j < nbRows ; ++j)
{
const int idx = get_idx(j, nbCols,i);
transposedData[idx] = std::move(mData[j][i]);
}
}
for(size_t i = 0 ; i < nbCols ; ++i)
{
for(size_t j = 0 ; j < nbRows ; ++j)
{
const int idx = get_idx(j, nbCols,i);
cout<<transposedData[idx]<<" ";
}
cout<<endl;
}
我想再次强调一下:分析您的代码。试用valgrind --tool= callgrind
或gprof
之类的软件,使您可以分析和可视化有关应用程序的性能数据。
答案 1 :(得分:1)
该程序在多个级别都有冗余。
显而易见的是,您无需为转置文件而转置向量。
vector<vector<string> originalData;
// read the file to originalData
for(size_t i = 0 ; i < nbCols ; ++i)
{
for(size_t j = 0 ; j < nbRows ; ++j)
{
cout << originalData[j][i] << " ";
}
cout<<endl;
}
假设由于某些原因确实需要产生转置向量,编写转置循环的一种方法是
vector<vector<string>> transposedData (nbCols);
for (size_t j = 0; j < nbCols; ++j)
{
transposedData[j].reserve(nrows);
for (size_t i = 0; i < nbRows; ++i)
{
transposedData[j].emplace_back(originalData[i][j]);
// if keeping original veector is not needed ...
// transposedData[j].emplace_back(std::move(originalData[i][j]));
}
}
在我的(相当强壮)的机器上,大约需要6-7秒来转置1000x90000的3个字符的字符串矩阵。这并不是特别令人印象深刻,如果您不需要每天24小时转置数百万个元素的矩阵,那么它就可以满足您的需要而没有太多的开销。
答案 2 :(得分:0)
惩罚可能是由于您在for循环中过度使用了调整大小的原因。
根据reference:
复杂度
当前大小和计数之间的线性差异。如果容量小于数量,则由于重新分配而可能导致额外的复杂性
内存分配的成本很高,因此您可能要避免过多使用内存。
正如其他人指出的那样,预先分配将是避免每次重新创建向量(调整大小)的有趣方法。
答案 3 :(得分:0)
我的计算机上没有足够的可用内存来执行此任务(请参见下文)。 将数据分为三个部分,我在几秒钟内解决了任务。 这是检查内存的代码的输出:
free ram 2.5GB IO populating mData with raw data free ram 0.2GB Empty string capacity : 15 bytes Intending to allocate 1.4 GB terminate called after throwing an instance of 'std::bad_alloc' what() : std::bad_alloc Aborted