1

当我遍历文件 A 中的行时,我正在解析该行并将每个字符串 ( char*) 放入char**.

在一行的末尾,我运行一个过程,该过程包括打开文件 B,使用fgets,fseekfgetc从该文件中获取字符。然后我关闭文件 B。

我为每一行重复重新打开和重新关闭文件 B。

我想知道的是:

  1. malloc使用and是否会对性能产生重大影响free,因此我应该使用静态的东西myArray[NUM_STRINGS][MAX_STRING_WIDTH]而不是动态的东西char** myArray

  2. 打开和关闭文件 B 是否有显着的性能开销(从概念上讲,数千次)?如果我的文件 A 已排序,有没有办法让我fseek在文件 B 中“向后”移动,以重置我之前在文件 B 中的位置?

编辑结果证明,一种双重方法大大减少了运行时间:

  1. 我的文件 B 实际上是二十四个文件之一。而不是打开同一个文件 B1 一千次,然后打开 B2 一千次,等等。我打开文件 B1 一次,关闭它,B2 一次,关闭它等等。这将数千次fopen操作减少fclose到大约 24 次。

  2. 我曾经rewind()重置文件指针。

这产生了大约 60 倍的速度提升,这已经绰绰有余了。谢谢你指点我rewind()

4

8 回答 8

4

如果您的动态数组随时间增长,则在某些reallocs 上存在复制成本。如果您使用“总是加倍”启发式,这将摊销到 O(n),所以它并不可怕。如果您提前知道大小,堆栈分配的数组仍然会更快。

对于第二个问题,请阅读rewind. 它必须比一直打开和关闭更快,并让您减少资源管理。

于 2009-06-12T19:07:53.017 回答
3

我想知道的是:

  • 你的代码工作正常吗?
  • 它的运行速度是否足以满足您的目的?

如果这两个答案都是“是”,则不要更改任何内容。

于 2009-06-12T19:10:24.807 回答
1

打开和关闭的开销取决于其他程序是否在竞争该资源。

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

你不会马上得到一个多维数组,而是一点指针算术,你就在那里。

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

于 2009-06-12T19:08:00.023 回答
1
  1. 如果您的文件很大,磁盘 I/O 将比内存管理昂贵得多。在分析之前担心 malloc/free 性能表明这是一个瓶颈是过早的优化。

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

于 2009-06-12T19:14:15.390 回答
0

使用动态内存总是会影响性能。使用静态缓冲区将提供速度提升。

重新打开文件也会对性能造成影响。您可以使用 fseek(pos, SEEK_SET) 将文件指针设置到文件中的任何位置,或者使用 fseek(offset, SEEK_CUR) 进行相对移动。

显着的性能影响是相对的,您必须确定这对自己意味着什么。

于 2009-06-12T19:09:21.173 回答
0
  1. 我认为最好分配您需要的实际空间,并且开销可能不会很大。这避免了浪费空间和堆栈溢出

  2. 是的。尽管 IO 已缓存,但您正在进行不必要的系统调用(打开和关闭)。将 fseek 与可能SEEK_CURSEEK_SET.

于 2009-06-12T19:10:08.830 回答
0

在这两种情况下,都会对性能产生一些影响,但重要性取决于文件的大小和程序运行的上下文。

  1. 如果你真的知道最大字符串数和最大宽度,这会快很多(但如果你使用少于“max”,你可能会浪费很多内存)。快乐的媒介是做 C++ 中的许多动态数组实现所做的事情:每当您必须重新分配 myArray 时,分配两倍于您需要的空间,并且只有在空间用完后才重新分配。这有 O(log n) 的性能成本。

  2. 这可能对性能造成很大影响。我强烈推荐使用 fseek,虽然细节取决于你的算法。

于 2009-06-12T19:10:26.303 回答
0

我经常发现附带的直接内存管理malloc和内存上的那些低级 C 处理程序超过了性能开销。除非这些内存区域将保持静态且未触及的时间量比触及该内存的摊销时间长,否则坚持使用静态数组可能更有益。最后,这取决于你。

于 2009-06-12T19:13:04.660 回答