1

这一切都始于这个问题->如何从文件中读取数据块,然后从该块读取到向量中?

为了最小化磁盘 I/O 操作,我进行了一些实验,看看缓冲区的大小是否对程序花费的时间有任何影响。

我使用了以下两个代码,一个是面向 c 的,另一个是 c++(尽管都是用 gcc 编译的):-

面向c的代码:-

int buffer_size=1024;
FILE *file;
file = fopen(argv[1], "r");
FILE *out_file;
out_file = fopen("in", "w");
char out_buffer[2048];
setvbuf(out_file, out_buffer, _IOFBF, buffer_size);
char buffer[2048];
setvbuf(file, buffer, _IOFBF, buffer_size);
while (!feof(file)) 
{
 char sl[1000];
 fgets(sl, 140 , file);
 fputs(sl, out_file);

}

c 代码给出了以下结果(对于 14 mb 文件):-

Buffer_size      Time
10               18 sec
100              2 sec
1024             0.4 sec              
10240            0.3 sec 

(对于 103 mb 文件)

1024             ~8 sec
5120             ~3 sec
10240            ~3 sec
15360            ~3 sec

它似乎在缓冲区大小约为 5 mb 时达到饱和点。这有什么特别的原因吗?

面向 c++ 的代码:-

int buffer_size=1024;
ifstream in_file(argv[1]);
char in_buffer[buffer_size];
in_file.rdbuf()->pubsetbuf(in_buffer,sizeof(in_buffer));
ofstream out_file("in");
char out_buffer[buffer_size];
out_file.rdbuf()->pubsetbuf(out_buffer,sizeof(in_buffer));
while(!in_file.eof())
{
    char sl[1024];
    in_file >> sl;
    out_file << sl<<endl;
}

我的测试输入文件是一个 14mb 的文件,有 1000000 行。

Buffer_size      Time (~)
10               6.5 sec
100              6.5 sec
1024             6.5 sec  

C++ 似乎根本不关心缓冲区大小。为什么?

此外,C++ 代码慢了大约 15 倍(当 C 中的缓冲区大小为 1 mb 时)!ifstream 通常比 FILE 慢(SO上的其他答案似乎表明没有区别)?或者代码中是否还有其他原因导致缓慢?

4

3 回答 3

2

从根本上说,写作所花费的时间是通过以下公式估算的:

T = C1*nsyscalls + C2*nbytes

实际上,C1是一个非常大的常数(每个系统调用的成本)并且C2是一个非常小的常数(每个字节的成本)。缓冲区的大小会影响比率的大小nsyscalls/nbytes;更大的缓冲区使其更小。缓冲的目标是nsyscalls相对于第二项支配第一项而言足够小nbytes,并且您只剩下T = (C2+epsilon)*nbytes. 一旦缓冲区足够大以至于第二项占主导地位,进一步增加缓冲区大小不会给您带来任何显着的性能提升。

于 2013-03-01T04:37:57.523 回答
2

众所周知,iostreams 中的格式化输入 >> 非常慢。但问题是您不要将苹果与苹果进行比较,因为 istream >> std::string 或 char * 正在读取由空格分隔的单词,而不是 fgets 所做的。因此,对 std::string 使用 std::getline 或对 char * 使用 istream::getline() 以具有类似的功能,并且您的比较会更有意义。

PS 在这个例子中 pubsetbuf() 在文件打开之前被调用。这可能是您在打开文件后调用 pubsetbuf() 时没有观察到代码中读取速度的任何变化的原因。

于 2013-03-01T04:33:02.670 回答
0

您的 C++ 代码的问题是无法在 streambuf 中设置缓冲区大小。调用pubsetbuf(0, 0)将使输出文件流无缓冲,但使用任何其他值不会做任何特别的事情。从规范:

basic_streambuf* setbuf(char_type* s, 流大小 n);

效果:如果在该流上发生任何 I/O 之前对该流调用 setbuf(0,0),则该流将变为无缓冲。否则结果是实现定义的。“无缓冲”意味着 pbase() 和 pptr() 总是返回 null 并且文件的输出应该尽快出现。

看起来在您的情况下,实现忽略了 setbuf ...

于 2013-03-01T07:25:15.547 回答