我需要從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()));
}
漂亮男人2017-05-31 10:38:40
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和轉換函數的開銷,真正達到秒取資料。
phpcn_u15822017-05-31 10:38:40
目前最有效率的辦法就是用流,而在你的程式碼實作中可以看出來:你是全部將文件內容一次性讀入buffer中,這種方式不是最好的。建議平均每次讀 buffer[1024] 也就是1K,或其他也可以。 讀完指針就移到下一行,繼續讀,直到EOF位置結束
天蓬老师2017-05-31 10:38:40
1.如果資料間沒有依賴關係的話,可以試試分塊多線程讀取;
2.另外vector的內存是連續的,如果後面不是要隨機訪問,而都是遍歷的話,用list效率會高不少。