我有一个接近800M的大文件,我想逐行阅读。
起初我用Python编写程序 ,我使用linecache.getline:
lines = linecache.getlines(fname)
成本约为1.2秒。
现在我想将我的程序移植到C ++。
我写了这些代码:
std::ifstream DATA(fname);
std::string line;
vector<string> lines;
while (std::getline(DATA, line)){
lines.push_back(line);
}
但它很慢(成本分钟)。如何改进?
mmap()
,并且在CreateFileMapping()
窗口上工作。我的代码在VS2013下运行,当我使用“DEBUG”模式时,需要162
秒;
当我使用“RELEASE”模式时,只有7
秒!
(非常感谢@DietmarKühl和@Andrew )
答案 0 :(得分:1)
对于c ++,您可以尝试这样的事情:
void processData(string str)
{
vector<string> arr;
boost::split(arr, str, boost::is_any_of(" \n"));
do_some_operation(arr);
}
int main()
{
unsigned long long int read_bytes = 45 * 1024 *1024;
const char* fname = "input.txt";
ifstream fin(fname, ios::in);
char* memblock;
while(!fin.eof())
{
memblock = new char[read_bytes];
fin.read(memblock, read_bytes);
string str(memblock);
processData(str);
delete [] memblock;
}
return 0;
}
答案 1 :(得分:1)
首先,您应该确保在编译时启用了优化。这对于这样一个简单的算法可能无关紧要,但这实际上取决于你的向量/字符串库实现。
正如@angew所建议的那样,std::ios_base::sync_with_stdio(false)对你所写的例程有很大的影响。
另一个较小的优化是使用lines.reserve()
预分配您的向量,以便push_back()
不会导致大量的复制操作。但是,如果您事先知道可能会收到多少行,这将非常有用。
使用上面建议的优化,我获得了以下读取800MB文本流的结果:
20 seconds ## if average line length = 10 characters
3 seconds ## if average line length = 100 characters
1 second ## if average line length = 1000 characters
正如您所看到的,速度主要受每行开销的影响。此开销主要发生在std::string
类中。
基于存储大量std::string
的任何方法很可能在内存分配开销方面不是最理想的。在64位系统上,std::string
将需要每个字符串16字节开销的最小。实际上,开销很可能远远大于开销 - 你可能会发现内存分配(std::string
内部)成为一个重要的瓶颈。
为了获得最佳的内存使用和性能,请考虑编写自己的例程,以大块方式读取文件,而不是使用getline()
。然后,您可以应用类似于flyweight pattern的内容来管理使用自定义字符串类对各行进行索引。
P.S。另一个相关因素是物理磁盘I / O,它可能会或可能不会被缓存绕过。