急求大神!!!!使用C++从文件中读取五千万个数据存入vector中如何加快速度?急急急急急急!!!

Mastli 学生  2017-05-23 09:04:08
我需要从txt文件中读取五千万个double数据,并且存入vector中,我最初觉得可能是文件io太慢,所以使用了文件内存映射,将文件内容当成block全部读入内存中,然后转换为string流,再一个一个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;
while (ss_sim.good()) {//从string流中读入vector
ss_sim >> fVecSim;
vec_similarity.push_back(atof(fVecSim.c_str()));
}
...全文
520 点赞 收藏 17
写回复
17 条回复
切换为时间正序
当前发帖距今超过3年,不再开放新的回复
发表回复
sichuanwww 2017-05-26
回复
ForestDB 2017-05-25

$ yes 1.0 | head -50000000 >5KW
$ head -2 5KW 
1.0
1.0
$ wc 5KW 
 50000000  50000000 200000000 5KW
$ cat a.cpp 
# include <iostream>
# include <fstream>
# include <vector>
# include <algorithm>
# include <iterator>

using namespace std;

int main()
{
    ifstream input("5KW");
    vector<double> v;
    cout << v.size() << endl;;
    copy(istream_iterator<double>(input),
         istream_iterator<double>(),
         back_inserter(v));
    cout << v.size() << endl;;
    cout << v[0] << endl;
    cout << v[v.size() - 1] << endl;

    return 0;
}
$ time ./a 
0
50000000
1
1

real	0m12.200s
user	0m11.316s
sys	0m0.152s


$ cat b.cpp 
# include <iostream>
# include <fstream>
# include <vector>
# include <algorithm>
# include <iterator>

using namespace std;

int main()
{
    ifstream input("5KW");
    vector<double> v(50000000);
    cout << v.size() << endl;;
    for (size_t i = 0; i < 50000000; i++)
        input >> v[i];
    cout << v.size() << endl;;
    cout << v[0] << endl;
    cout << v[v.size() - 1] << endl;

    return 0;
}
$ time ./b
50000000
50000000
1
1

real	0m10.103s
user	0m9.272s
sys	0m0.064s

一开始就把空间分配好,确实会快,可是只是快了那么一点点。时间都消耗在io上了。

$ cat c.cpp 
# include <iostream>
# include <fstream>
# include <vector>
# include <algorithm>
# include <iterator>

using namespace std;

int main()
{
    ifstream input("5KW");
    double * v = new double[50000000];
    for (size_t i = 0; i < 50000000; i++)
        input >> v[i];
    cout << v[0] << endl;
    cout << v[50000000 - 1] << endl;

    return 0;
}
$ time ./c 
1
1

real	0m9.516s
user	0m9.064s
sys	0m0.076s

$ cat d.cpp 
# include <iostream>
# include <fstream>
# include <vector>
# include <algorithm>
# include <iterator>
# include <cstdio>

using namespace std;

int main()
{
    FILE * input = fopen("5KW", "r");
    double * v = new double[50000000];
    for (size_t i = 0; i < 50000000; i++)
        fscanf(input, "%lf", &v[i]);
    cout << v[0] << endl;
    cout << v[50000000 - 1] << endl;

    return 0;
}
$ time ./d 
1
1

real	0m6.250s
user	0m5.844s
sys	0m0.056s

看上去用array比用vector好,c的io比c++的io好。
LZ应该是在读5亿个数据才对吧。
回复
赵4老师 2017-05-25
容量大小从小到大:栈≤全局数据≤堆≤文件≤硬盘≤磁盘阵列≤云存储 当程序需要使用比如2GB~1TB左右的存储时,最简单的办法恐怕得是用文件读写模拟内存读写了吧。windows参考_fseeki64函数,linux参考fseeko64函数。
FILE *fA;fA=fopen("A","rb+");_fseeki64(fA,10000000000i64*sizeof(int),SEEK_SET);fputc(fA,0);//int A[10000000000];
int B;
_fseeki64(fA,9999999999i64*sizeof(int),SEEK_SET);fread(&B,1,sizeof(int),fA);//B=A[9999999999];
_fseeki64(fA,9999999999i64*sizeof(int),SEEK_SET);fwrite(&B,1,sizeof(int),fA);//A[9999999999]=B;
fclose(fA);
回复
bravery36 2017-05-25
其实我觉得初始化的过程也没有太多可以优化的了,快一些意义何在?一般的精力都是在查找或其他操作上优化。lz你确定想做的事是这个吗?
回复
ForestDB 2017-05-24
“文件内存映射”这个想法是对的,但不是你这么个搞法,应该用mmap。
回复
ForestDB 2017-05-24
你所谓的优化,多花了两分钟在把文件读入内存中。
回复
ForestDB 2017-05-24
另外你用的还是push_back,你前面reserve的就白搭了。
回复
赵4老师 2017-05-24
在文件大小相同的前提下: 读刚读过的文件比头次读没读过的文件快 读转速快的硬盘上的文件比读转速慢的硬盘上的文件快 读没有磁盘碎片的文件比读有磁盘碎片的文件快 读文件不处理比边读边处理快 单线程从头到尾一次读文件比多线程分别读文件各部分快(非固态硬盘上) 读固态硬盘上的文件比读普通硬盘上的文件快 您是否希望迅速对您频繁使用的文件进行碎片整理?使用 Contig 优化单个的文件,或者创建连续的新文件。http://technet.microsoft.com/zh-cn/sysinternals/bb897428
回复
ForestDB 2017-05-24
       
        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);  // 这里虽说系统有copy on write,但语义上还是有一次copy的动作。
        delete[]buffer;

        istringstream ss_sim(input);//string流

        string fVecSim;
        while (ss_sim.good()) {//从string流中读入vector
            ss_sim >> fVecSim;
            vec_similarity.push_back(atof(fVecSim.c_str()));
        }
本来你new一个文件流对象,然后直接读就是了,被你优化后,又是文件io,又是内存copy。 已经提示了可以试试mmap。 另外到了这个量级,你的算法基本上得设计下了。
回复
Mastli 2017-05-24
引用 7 楼 paschen 的回复:
vector 先 reserve 或 resize 预分配空间
版主您好,我使用reserve分配了五千万的容量vec_similarity.reserve(50000000); 但是读入时间大概到了6分钟,请问性能瓶颈到底在哪儿呢?
回复
paschen 版主 2017-05-24
vector 先 reserve 或 resize 预分配空间
回复
Mastli 2017-05-24
引用 3 楼 ForestDB 的回复:
“文件内存映射”这个想法是对的,但不是你这么个搞法,应该用mmap。
是不是优化的方向错了呢? 我用了reserve分配了五千万的容量。请问五千万个数据读进vector会不会是我的性能瓶颈呢?
回复
Mastli 2017-05-24
引用 1 楼 jpl910192883 的回复:
IO操作只是将数据流和文件关联,然后操作指针对文件读写,并不会将文件整个读入内存。你将文件整个读入内存,首先空间上实不可取的,效率上和IO也没什么区别,都是将数据从硬盘写入内存,IO操作指针的效率是很高的。你应该将效率提升的方向放在对vector存取的效率提升上面,vector本质上是一个动态数组,默认长度肯定无法满足你的要求,所以一旦你存取的内容远远超过vector的大小,它就会频繁的去(申请新内存,copy数组到新内存,销毁旧内存),所以提前给vector分配一个足够大的内存可以显著提高效率。。。个人观点,欢迎指正
我用reserve给vector提前分配了五千万的容量,但是性能提升还是不明显啊,请问这是为什么呢?难道是我的方法有问题? 我是这样写的: vec_name.reserve(50000000); 请问是写错了么?
回复
ldxab 2017-05-24
帮顶,一起学习
回复
std::list试一下? 不行的话那就不要用stl咯
回复
paschen 版主 2017-05-24
引用 8 楼 xdz78 的回复:
[quote=引用 7 楼 paschen 的回复:] vector 先 reserve 或 resize 预分配空间
版主您好,我使用reserve分配了五千万的容量vec_similarity.reserve(50000000); 但是读入时间大概到了6分钟,请问性能瓶颈到底在哪儿呢?[/quote] VS自带性能分析工具,可以统计语句的耗时,查找瓶颈
回复
IO操作只是将数据流和文件关联,然后操作指针对文件读写,并不会将文件整个读入内存。你将文件整个读入内存,首先空间上实不可取的,效率上和IO也没什么区别,都是将数据从硬盘写入内存,IO操作指针的效率是很高的。你应该将效率提升的方向放在对vector存取的效率提升上面,vector本质上是一个动态数组,默认长度肯定无法满足你的要求,所以一旦你存取的内容远远超过vector的大小,它就会频繁的去(申请新内存,copy数组到新内存,销毁旧内存),所以提前给vector分配一个足够大的内存可以显著提高效率。。。个人观点,欢迎指正
回复
相关推荐
发帖
C++ 语言
创建于2007-09-28

6.0w+

社区成员

C++ 语言相关问题讨论,技术干货分享,前沿动态等
申请成为版主
帖子事件
创建了帖子
2017-05-23 09:04
社区公告
暂无公告