2009-06-12 86 views
1

当我循环遍历文件A中的行时,我正在解析行并将每个字符串(char*)放入char**C malloc/free + fgets性能

在行尾,我运行一个包含打开文件B的过程,使用fgets,fseekfgetc来抓取该文件中的字符。然后关闭文件B.

我重复重新打开并重新关闭文件B的每一行。

我想知道的是:

  1. 是否有使用mallocfree一个显著的性能损失,这样,我应该使用什么样的静态的myArray[NUM_STRINGS][MAX_STRING_WIDTH]而不是动态char** myArray

  2. 是否有打开和关闭文件B(概念上,数千次)的显着性能开销?如果我的文件A已排序,是否有一种方法可以让我使用fseek在文件B中向后移动,以重置之前位于文件B中的位置?

编辑原来,两方面的做法大大降低了运行时:

  1. 我的文件B其实是24文件中的一个。我打开B1文件B1一次,关闭它,B2打开一次,关闭它,等等,而不是打开相同的文件B1千次,然后打开B2一千次。这将操作的数千个操作减少到大约几千个24.

  2. 我用rewind()来重置文件指针。

这产生了大约60倍的速度改进,这是绰绰有余。感谢您指点我rewind()

+0

如果你不得不跳回到一个特定的*,以前在文件中的位置(而不是开始),你可能也想看看fgetpos()和fsetpos()。 – DevSolar 2009-11-12 10:46:57

回答

4

如果您的动态阵列及时增长,则在某些realloc s上会有复制成本。如果你使用“总是双重”启发式,这将分摊到O(n),所以它并不可怕。如果您提前知道大小,堆栈分配数组仍然会更快。

对于第二个问题阅读关于rewind。它的速度要比打开和关闭都快,并且可以减少资源管理。

+4

从历史上看,在大多数操作系统上,文件打开/关闭操作已被证明是非常昂贵的。 – 2009-06-12 19:10:04

+0

@Briam提供证据的链接? – 2009-06-12 19:13:53

+0

我实际上并没有重新分配,但是一旦我完成了这一行,就做了一个malloc,之后是一个free()。然后我再次在随后的行上使用malloc-free。 – 2009-06-12 19:15:24

1

打开和关闭有一个可变的开销,取决于其他程序是否竞争资源。

首先测量文件大小,然后使用它来预先计算数组大小以执行一次大堆分配。

你不会立即得到一个多维数组,但有一点指针算术,你在那里。

你不能在另一个文件中缓存位置信息,然后,而不是打开和关闭它,使用以前的查找索引作为偏移?取决于确切的逻辑。

0

使用动态内存时总会有性能问题。使用静态缓冲区将提供速度提升。

重新打开文件也会导致性能下降。您可以使用fseek(pos,SEEK_SET)将文件指针设置为文件中的任何位置或fseek(offset,SEEK_CUR)来执行相对移动。

显着的性能影响是相对的,您将不得不确定自己的意思。

0
  1. 我觉得这是更好地分配你需要的 实际空间, 开销可能不会 显著。这避免了 浪费空间和堆栈溢出

  2. 是的。虽然IO被缓存,但是您正在使不必要的系统调用 (打开和关闭)。使用fseek 或许SEEK_CURSEEK_SET

3

我想知道的是:

  • 正确地做你的代码的工作?
  • 运行速度足够快吗?

如果答案都是“是”,请不要更改任何内容。

0

在这两种情况下,有一些的性能损失,但意义将取决于文件的大小和上下文你的程序在运行。

  1. 如果你确实知道的最大数量字符串和最大宽度,这将会快很多(但是如果使用小于“最大”的值,则可能浪费大量内存)。幸运的是,要做C++中的很多动态数组实现:无论何时必须重新分配myArray,根据需要分配两倍的空间,并且只在空间不足时再次重新分配。这具有O(log n)性能成本。

  2. 这可能是一个很大的表现。我强烈建议使用fseek,但细节将取决于您的算法。

0

我经常发现的性能开销通过自带的内存malloc和那些低C级处理器的直接存储器管理来抵消。除非这些区域的内存将保持静态并且在触摸此内存的分摊时间内保持不变,否则使用静态数组可能更有利。最后,这取决于你。

1
  1. 如果您的文件很大,磁盘I/O会比内存管理贵得多。在分析之前担心malloc/free性能表明它是瓶颈是过早的优化。

  2. 在您的程序中,频繁开启/关闭的开销可能很大,但实际的I/O再次可能会更加昂贵,除非文件很小,在这种情况下,关闭和打开可能会导致额外的磁盘I/O。是的,您可以使用ftell()获取文件中的当前位置,然后使用SEEK_SET获取该位置。