问题描述
我需要从txt文件中读取五千万个double数据,并且存入vector中,我最初觉得可能是文件io太慢,所以使用了文件内存映射,将文件内容当成block全部读入内存中,然后再一个一个push_back进vector中,但是直接从文件一个一个读数据只需要3分钟,我优化之后反而增加到了5分钟。
我的优化方案是,将文件整块读入内存,放在char*的buffer中,再使用vec_name.reserve(50000000);分配五千万的容量,避免重复分配内存,但是好像没有什么作用。
难道是因为时间主要花在push_back上面了么?
请问有什么好的优化方法么?谢谢各位大神了!优化后的关键代码如下:(需要五分钟才能将全部数据读入vector)
ifstream iVecSim('input.txt');iVecSim.seekg(0, iVecSim.end);long long file_size = iVecSim.tellg();//文件大小iVecSim.seekg(0, iVecSim.beg);char *buffer = new char[file_size];iVecSim.read(buffer, file_size);string input(buffer);delete[]buffer;istringstream ss_sim(input);//string流string fVecSim;vec_similarity.reserve(50000000);while (ss_sim.good()) {//从string流中读入vector ss_sim >> fVecSim; vec_similarity.push_back(atof(fVecSim.c_str()));}
问题解答
回答1:debug模式下跑没有意义,我用你的代码在release下跑也就14秒左右的样子。
解决问题先找问题,我把代码修改成这个样子,先查出耗时的地方是哪
std::cout << 'Start' << std::endl; auto n1 = ::GetTickCount(); auto n2 = 0; auto n3 = 0; auto n4 = 0; while (ss_sim.good()) {auto n = ::GetTickCount();ss_sim >> fVecSim;n2 += (::GetTickCount() - n);n = ::GetTickCount();auto v = atof(fVecSim.c_str());n3 += (::GetTickCount() - n);n = ::GetTickCount();vec_similarity.push_back(v);n4 += (::GetTickCount() - n); } n1 = ::GetTickCount() - n1; std::cout << 'ss_sim >> fVecSim:' << n2 << 'ms' << std::endl; std::cout << 'atof:' << n3 << 'ms' << std::endl; std::cout << 'push_back:' << n4 << 'ms' << std::endl; std::cout << 'Total:' << n1 << 'ms' << std::endl;
所以瓶颈在于'ss_sim >> fVecSim'这一句。atof也已经够快了。
所以我的结论是:终极的优化方案是从存储格式上下手,将你的数据存储为二进制而非字符串,这样就避免了字符串IO和转换函数的开销,真正达到秒取数据。
回答2:目前最高效的办法就是用流,而在你的代码实现中可以看出来:你是全部将文件内容一次性读入buffer中,这种方式不是最好的。建议平均每次读 buffer[1024] 也就是1K,或者其他也可以。 读完指针就移到下一行,继续读,直到EOF位置结束
回答3:1.如果数据间没有依赖关系的话,可以试试分块多线程读取;2.另外vector的内存是连续的,如果后面不是要随机访问,而都是遍历的话,用list效率会高不少。
回答4:可以换用C风格的scanf试试
哇怎么这么对待我答案的?举报我的网友倒是说说,这答案怎么就有问题了?