【问题标题】:Reading 1 GB binary file taking too long in C在 C 中读取 1 GB 二进制文件花费的时间太长
【发布时间】:2016-05-16 13:08:57
【问题描述】:

我正在读取一个文件,其中输入元组的数量“n_tups”和单个元组的长度或其维度“d”。我已经为二维数组“元组”分配了如下内存。

当我运行代码时,我的计算机挂起,我不知道为什么。

if((fpp = fopen("in2.bin", "rb"))==NULL)
   printf("file in2.bin doesn't exist!");
else
{
 int **tuple;
 unsigned long i;

 tuple = malloc(n_tups * sizeof(int *));

 if(tuple == NULL)
   {
      fprintf(stderr, "out of memory\n");
      return;
   }
 for(i=0;i<n_tups;i++){
        tuple[i]=malloc(d * sizeof(int));
        if(tuple[i] == NULL)
        {
           fprintf(stderr, "out of memory\n");
           return;
         }  
  }

 fseek( fpp , 0 , SEEK_SET );
 printf("reading step");
 for(i=0;i<n_tups;i++){
         fread(&tuple[i],4,d,fpp);
         fread(&score[i],8,1,fpp);
    }

 fclose(fpp);
 }

我试图检查程序是否到达“读取步骤”,但它没有。原来它忙于分配内存! 我正在传递 d=3 n_tups=85013600 并且我的计算机有 4 GB 的 RAM。

【问题讨论】:

  • n_tupsd 传递了什么?你的电脑有多少内存?
  • 为什么是48 而不是sizeof(_something_)
  • @chux 它已被制造商指定为此 bin 文件的属性
  • @She 你错过了 chux 的观点:你的程序应该有一个正确大小的相应数据结构。那么你就不需要“幻数” 4 和 8。想到 int32_tint64_t
  • 另见Is malloc slow?。假设 150 万 malloc/秒,您的循环将花费 57 秒。假设 300 000 malloc/秒,您的循环将花费 284 秒。

标签: c file-handling


【解决方案1】:

代码本身存在两个性能问题。

  • 即使所有维度都相同,您也不必要地使用指针到指针查找表。使用二维数组会好得多,这样所有数据都分配在相邻的内存中。这样一来,CPU 不必每次读取堆时都在 RAM 中进行挖掘,而是可以利用数据缓存内存。

    像这样:

    int (*tuple)[d] = malloc( sizeof(int[n_tups][d]) );
    ...
    free(tuple);
    
  • 每次调用fread 都会很昂贵。尝试在每次调用时读取尽可能大的块。我不知道在您的情况下什么是最佳的-它取决于系统。但是为小块数据调用它是无效的。特别是因为正确编写的程序将始终检查每个 fread 调用的结果。

    理想情况下,假设您遵循我之前关于使用 2D 数组的建议,您只需要这样做:

    result = fread(tuple, sizeof(int[n_tups][d]), 1, fpp);
    

    但是,该文件似乎包含您希望存储在其他地方的不相关数据。考虑用单个结构数组替换两个int 数组,这样您每次可以读取更长的内存块。 (但是,思维结构填充。)

    请注意,从磁盘读取非常大的数据块可能会很耗时,因此请考虑从不同的线程而不是从主(GUI?)线程进行。

【讨论】:

  • 所以如果我在不同的线程中运行它,我的 gui 不会挂起?那需要posix吗?
  • @She 这取决于它用于什么系统。如果可用,POSIX pthread 可能是最好的选择。 Windows 等其他系统有自己的不可移植线程库。
  • fread() 应该不会太糟糕 - STDIO 调用通常缓冲 4k 或 8k 或数据,结合正常的文件系统页面缓存应该允许正常的 fread() 获得最大值的 90+% IO 费率。问题是“什么是‘最大 IO 速率’”?磁盘是由性能不佳的商品磁盘控制器连接的大型 S-L-O-W 5,400 RPM SATA 驱动器,系统上运行的所有其他设备都在使用该驱动器?这样的磁盘可能很幸运,每秒只能维持 30-40 次 IO 操作。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-03-06
  • 2016-03-24
  • 2018-11-14
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多