请STL高手帮忙:怎么加速fstream(ofstream, ifstream)的操作

边城狂人 2007-09-04 10:41:10
首先说明,输入输出都是二进制的方式,也就是用ofstream的write输出,用ifstream的read读入。

现在有一个测试用的结构
struct Test {
int v1;
int v2;
int v3;
int v4;
int v5;
int v6;
}

产生1000000个对象用于输出测试(保存在一个std::vector中)。

for (int i = 0; i < 1000000; i++) {
Test& t = v[i];
out.write((const char*) &v1, sizeof(int));
out.write((const char*) &v2, sizeof(int));
out.write((const char*) &v3, sizeof(int));
out.write((const char*) &v4, sizeof(int));
out.write((const char*) &v5, sizeof(int));
out.write((const char*) &v6, sizeof(int));
}

这样写1000000条数据的时间是26秒左右。

如果我自己定义一个缓冲类来写,时间会在7秒左右。自定义的缓冲类如下:

class MyOStream : public ofstream
{
public:
static const BUF_SIZE = 10240;

MyOStream(const char* filename, ios_base::openmode _Mode = ios_base::out)
: ofstream(filename, _Mode), current(0) {}

void write(const char* buffer, unsigned int size)
{
if (current + size > BUF_SIZE) {
this->flush();
}
memcpy(this->buffer, buffer, size);
current += size;
}

void flush()
{
ofstream::write(this->buffer, current);
current = 0;
}

private:
char buffer[BUF_SIZE];
int current;
};

_____________________________________________________
现在问题是——用什么办法,不使用自定义的输出流,只使用std的缓冲机制,把速度提升起来!!

我试过out.rdbuf()->setbuf(....),设置了一个100K的缓冲区,输出操作同样消耗26秒左右的时间,似乎缓冲区没起到作用,不知为何?

注,所有时间以自己机器上为准,机器不同时间肯定是不同的。
...全文
1622 38 打赏 收藏 转发到动态 举报
写回复
用AI写文章
38 条回复
切换为时间正序
请发表友善的回复…
发表回复
边城狂人 2007-09-05
  • 打赏
  • 举报
回复
Holmescn(Holmes·Conan) ( ) 信誉:100 2007-09-05 11:43:47 得分: 0
试试在打开fstream之前用 setbuf改buffer
____________________________________________

看看楼上,已经试过了
边城狂人 2007-09-05
  • 打赏
  • 举报
回复
代码
___________________________________________________

#include <iostream>
#include <fstream>
#include <vector>
#include <time.h>

using namespace std;

class Test {
public:
int v1;
int v2;
int v3;
int v4;
int v5;
int v6;

public:
Test(int v) {
v1 = v2 = v3 = v4 = v5 = v6 = v;
}
};

class MyOStream {
public:
static const unsigned int BUF_SIZE = 102400;

MyOStream(const char* filename) :
out(filename, ios_base::binary), current(0) {
}

void write(const char* buffer, unsigned int size) {
if (current + size > BUF_SIZE) {
this->flush();
}
memcpy(this->buffer, buffer, size);
current += size;
}

void flush() {
if (current == 0) {
return;
}
out.write(buffer, current);
current = 0;
}

void close() {
flush();
out.close();
}

private:
ofstream out;
char buffer[BUF_SIZE];
int current;

};

void write(ostream& out, const Test& test) {
out.write((const char*) &test.v1, sizeof(int));
out.write((const char*) &test.v2, sizeof(int));
out.write((const char*) &test.v3, sizeof(int));
out.write((const char*) &test.v4, sizeof(int));
out.write((const char*) &test.v5, sizeof(int));
out.write((const char*) &test.v6, sizeof(int));
}

void write2(ostream& out, const Test& test) {
out.rdbuf()->sputn((const char*) &test.v1, sizeof(int));
out.rdbuf()->sputn((const char*) &test.v2, sizeof(int));
out.rdbuf()->sputn((const char*) &test.v3, sizeof(int));
out.rdbuf()->sputn((const char*) &test.v4, sizeof(int));
out.rdbuf()->sputn((const char*) &test.v5, sizeof(int));
out.rdbuf()->sputn((const char*) &test.v6, sizeof(int));
}

void write4(MyOStream& out, const Test& test) {
out.write((const char*) &test.v1, sizeof(int));
out.write((const char*) &test.v2, sizeof(int));
out.write((const char*) &test.v3, sizeof(int));
out.write((const char*) &test.v4, sizeof(int));
out.write((const char*) &test.v5, sizeof(int));
out.write((const char*) &test.v6, sizeof(int));
}

void outputTime(const char* message, const clock_t& clk1, const clock_t& clk2) {
cout << message << " (ms): "<< (clk2 - clk1)<< endl;
}

void outputTime(const char* message, const clock_t& clk1) {
clock_t clk2 = clock();
outputTime(message, clk1, clk2);
}

int main() {
const int COUNT = 1000000;
clock_t clk = clock();

vector<Test> data;
for (int i = 0; i < COUNT; i++) {
data.push_back(Test(i));
}

outputTime("Create data vector", clk);

clk = clock();

ofstream out("f:\\test.bin", ios_base::binary);
for (int i = 0; i < COUNT; i++) {
const Test& test = data[i];
write(out, test);
}
out.close();

outputTime("Write all data without buffer", clk);

clk = clock();

ofstream out2("f:\\test2.bin", ios_base::binary);
for (int i = 0; i < COUNT; i++) {
const Test& test = data[i];
write2(out2, test);
}
out2.close();

outputTime("Write all data with buffer", clk);

clk = clock();

ofstream out3("f:\\test3.bin", ios_base::binary);
char buffer[102400];
out3.rdbuf()->pubsetbuf(buffer, 102400);
for (int i = 0; i < COUNT; i++) {
const Test& test = data[i];
write2(out3, test);
}
out3.close();

outputTime("Write all data with big buffer", clk);

clk = clock();

MyOStream out4("f:\\test4.bin");
for (int i = 0; i < COUNT; i++) {
const Test& test = data[i];
write4(out4, test);
}
out4.close();

outputTime("Write all data with my buffer", clk);
}
边城狂人 2007-09-05
  • 打赏
  • 举报
回复
Chiyer(星羽) ( ) 信誉:100 2007-09-04 22:50:09 得分: 0
上次这个好像快了n多
————————————————————————
是快了很多,差不多快了一倍,但是比我自己实现的Stream还是慢多了


cnvb(壮士沈) ( ) 信誉:100 2007-09-04 23:18:33 得分: 0
为什么要把变量定义放在循环内??好像编译器也不一定会优化吧??说错了请不吝扔砖....
————————————————————
定义的引用,理论上不会影响效率的。



看看我分别用VS2003和MinGW G++ 3.4.2编译之后跑的结果,跑了10次,下面是平均值
————————————————————————————————————
VS2003的
Create data vector (ms) 3925
Write all data without buffer (ms) 34038
Write all data with buffer (ms) 11352
Write all data with big buffer (ms) 11075
Write all data with my buffer (ms) 2882

G++的
Create data vector (ms) 258
Write all data without buffer (ms) 2505
Write all data with buffer (ms) 1791
Write all data with big buffer (ms) 2085
Write all data with my buffer (ms) 2689

看得出来,我自己写的OStream在VS2003中很占优势,但在G++中就慢了
总的来说使用默认的缓冲都比较快
但在VS2003中,效率明显提高,在G++中却不是那么明显

一会儿把代码帖出来给大家研究
Holmescn 2007-09-05
  • 打赏
  • 举报
回复
试试在打开fstream之前用 setbuf改buffer
jeffchen 2007-09-05
  • 打赏
  • 举报
回复
Debug版不做任何优化,还有很多调试信息,当然慢了。
边城狂人 2007-09-05
  • 打赏
  • 举报
回复
jeffchen(Jeff)
都是用Debug版本测试的。
VS2003是,G++也是。

如果Release比较快的话……看样子是Debug的时候不知道干了啥。回头Release测试一下。
jeffchen 2007-09-05
  • 打赏
  • 举报
回复
补充一下,我的机器是Celeron D 2.8G,RAM 1G
jeffchen 2007-09-05
  • 打赏
  • 举报
回复
不知lz的编译和运行环境如何?
我用vs2005、stlport 5.1.2、release版的情况下,直接使用ofstream输出,平均耗时也是2秒左右;最大耗时也是3秒多。代码如下:
#include "stdafx.h"
#include <fstream>
#include <iostream>
#include <Windows.h>

using namespace std;

struct Test {
int v1;
int v2;
int v3;
int v4;
int v5;
int v6;
};

int _tmain(int argc, _TCHAR* argv[])
{
ofstream out("text.txt", ios_base::binary);

Test* v = new Test[1000000];

DWORD s = GetTickCount();

for (int i = 0; i < 1000000; i++) {
Test& t = v[i];
out.write((const char*) &t.v1, sizeof(int));
out.write((const char*) &t.v2, sizeof(int));
out.write((const char*) &t.v3, sizeof(int));
out.write((const char*) &t.v4, sizeof(int));
out.write((const char*) &t.v5, sizeof(int));
out.write((const char*) &t.v6, sizeof(int));
}
out.flush();

DWORD d = GetTickCount();

cout<<(d - s) / 1000.f<<endl;

return 0;
}

星羽 2007-09-05
  • 打赏
  • 举报
回复
楼主你可以跟一下ostream::write 里面好象很复杂,调来调去的

还用了 fputc 只类的,我们设置的那个缓冲,其实内部就是调用

setbuf(FILE* p, char* buffer);

。。。

我怀疑是write的复杂性,一直调用次数过多带来效率的影响
边城狂人 2007-09-05
  • 打赏
  • 举报
回复
更正一处错误,在MyOStream的write函数中,这一句有错
memcpy(this->buffer, buffer, size);
忘了加缓存指针偏移,应该改为
memcpy(&this->buffer[current], buffer, size);

另外,如果有比buffer大的数据进来,这个程序也会出错,所以加了一句判断在前面:
void write(const char* buffer, unsigned int size) {
if (size > BUF_SIZE) {
this->flush();
out.write(buffer, size);
return;
}
if (current + size > BUF_SIZE) {
this->flush();
}
memcpy(&this->buffer[current], buffer, size);
current += size;
}
mgtcllxl 2007-09-05
  • 打赏
  • 举报
回复
mark
边城狂人 2007-09-05
  • 打赏
  • 举报
回复
chang19() ( ) 信誉:100

你那个写法虽然快,但是几本上只能用于试验。
真实的数据结构里很复杂的,而且涉及指针引用之类的东西,写是没问题,以后读的时候就问题大了。
systemthink 2007-09-05
  • 打赏
  • 举报
回复
MARK!
缔峰泽科技 2007-09-05
  • 打赏
  • 举报
回复
//大哥们为什么不这么写0.4s
#include <tchar.h>
#include <fstream>
#include <iostream>
#include <Windows.h>

using namespace std;

struct Test {
int v1;
int v2;
int v3;
int v4;
int v5;
int v6;
Test()
{
v1=v2=v3=v4=v5=v6=0;
}
};

int _tmain(int argc, _TCHAR* argv[])
{
ofstream out("text.txt", ios_base::binary);

Test* v = new Test[1000000];
//memset(&v[999999],1,sizeof(Test));
DWORD s = GetTickCount();
out.write((char*)v,sizeof(Test)*1000000);
//for (int i = 0; i < 1000000; i++) {
// Test& t = v[i];
// out.write((const char*) &t.v1, sizeof(int));
// out.write((const char*) &t.v2, sizeof(int));
// out.write((const char*) &t.v3, sizeof(int));
// out.write((const char*) &t.v4, sizeof(int));
// out.write((const char*) &t.v5, sizeof(int));
// out.write((const char*) &t.v6, sizeof(int));
//}
out.flush();

DWORD d = GetTickCount();

cout<<(d - s) / 1000.f<<endl;

return 0;
}
边城狂人 2007-09-05
  • 打赏
  • 举报
回复
raymonzhao(Raymon)
MARK一下先.我现在的程序现在都不要求很高的效率,稳定和易维护才是考虑的重点.

_____________________________________________________

你做应用当然不用太考虑效率,但是偶要做底层,不考虑效率不行啊……!
raymonzhao 2007-09-05
  • 打赏
  • 举报
回复
MARK一下先.我现在的程序现在都不要求很高的效率,稳定和易维护才是考虑的重点.
cnvb 2007-09-04
  • 打赏
  • 举报
回复
为什么要把变量定义放在循环内??好像编译器也不一定会优化吧??说错了请不吝扔砖....
我啃 2007-09-04
  • 打赏
  • 举报
回复
说说原始的需求
边城狂人 2007-09-04
  • 打赏
  • 举报
回复
对于一个简单的数据结构是这样,但是实际的数据结构很复杂的。
比如 class A 里包括了 B的指针和 B的指针数组——这些都是需要在序列化过程中处理的,所以不能直接写vector的内存啊。
直接写我也试过,9秒,比用MyOStream还慢3秒。
www_adintr_com 2007-09-04
  • 打赏
  • 举报
回复
你这样循环花在函数调用上的时间就不少了, vector 保证了内存布局的,这样就快了:
out.write((char*)&v[0], v.size() * sizeof(Test));
加载更多回复(18)

64,281

社区成员

发帖
与我相关
我的任务
社区描述
C++ 语言相关问题讨论,技术干货分享,前沿动态等
c++ 技术论坛(原bbs)
社区管理员
  • C++ 语言社区
  • encoderlee
  • paschen
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
  1. 请不要发布与C++技术无关的贴子
  2. 请不要发布与技术无关的招聘、广告的帖子
  3. 请尽可能的描述清楚你的问题,如果涉及到代码请尽可能的格式化一下

试试用AI创作助手写篇文章吧