为什么移动缓冲区指针会减慢fread(C编程语言)?

我正在使用C中的fread读取1 GB文件。我正在使用以下循环以1MB块读取文件:

FILE *fp; fp = fopen(filename, "rb"); unsigned char* buf; buf = malloc(CHUNK_SIZE); for(i = 0; i < NUMBER_OF_CHUNKS; ++i) { fread(buf, CHUNK_SIZE, 1, fp); //Do something with contents of buffer } fclose(fp); 

以这种方式读取文件大约需要2秒钟。

但是,我决定我想为整个文件的内容分配一个大缓冲区,并在每次迭代时在fread函数内“移动缓冲区指针”,如下所示:

 FILE *fp; fp = fopen(filename, "rb"); unsigned char* buf; buf = malloc(CHUNK_SIZE * NUMBER_OF_CHUNKS); for(i = 0; i < NUMBER_OF_CHUNKS; ++i) { fread(&buf[i*CHUNK_SIZE], CHUNK_SIZE, 1, fp); } fclose(fp); 

这显着减慢了读数,现在大约需要40秒。

我的问题是:

  1. 为什么这会对性能产生如此巨大的影响?
  2. 如果我想以第二种方式阅读文件,你会建议我做什么,但我想保持时间低?

该文件由一行字母数字字符组成。

我想以第二种方式阅读它,以便我可以让其他线程访问已经读取的缓冲区中的块,而读取线程继续填充缓冲区的其余部分。

谢谢!

您的计算机可能内存不足。 一个千兆字节需要分配很多内存。 你的操作系统我必须将一些数据交换到磁盘,这将导致一个数量级的减速。

您可以考虑单独分配每个块,并在完成后释放它们。 这样,程序的总内存使用量受工作集的限制,而不是整个文件。

当内存不足并且操作系统在交换分区中来回切换时,您不仅会导致大约3倍的磁盘流量。 此外,对于机械/旋转硬盘[是的,那些仍然很常见],头部需要来回寻找交换空间和您正在阅读的文件 – 即使文件没有碎片。 这很可能会造成10-15倍的额外速度惩罚。

一种可能的解决方法是使用mmap将内存映射为连续内存,允许操作系统决定最佳交换策略。