【问题标题】:C malloc/free + fgets performanceC malloc/free + fgets 性能
【发布时间】:2009-06-12 19:03:01
【问题描述】:

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

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

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

我想知道的是:

  1. 使用mallocfree 是否会显着影响性能,因此我应该使用myArray[NUM_STRINGS][MAX_STRING_WIDTH] 之类的静态而不是动态char** myArray

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

编辑事实证明,双重方法大大减少了运行时间:

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

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

这使速度提高了大约 60 倍,这绰绰有余。感谢您将我指向rewind()

【问题讨论】:

  • 如果您必须跳回一个特定,以前在文件中的位置(而不是开头),您可能还需要检查 fgetpos() 和fsetpos().

标签: c performance malloc fseek


【解决方案1】:

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

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

【讨论】:

  • 从历史上看,文件打开/关闭操作在大多数操作系统上被证明是非常昂贵的。
  • @Briam 链接到可以为此提供证据的东西?
  • 我实际上并没有重新分配,而是执行 malloc 后跟 free(),一旦我完成了该行。然后我在后续行中再次释放 malloc。
  • @alex 在您的问题中发布一些示例代码可能是一个好主意。
【解决方案2】:

我想知道的是:

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

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

【讨论】:

  • 这是一个意见,而不是一个答案。
【解决方案3】:

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

先测量文件大小,然后用它提前计算数组大小,做一个大堆分配。

你不会马上得到一个多维数组,但是一点点指针运算就可以了。

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

【讨论】:

  • 这不会让每一行都是一个单独的元素。这实际上可能有必要,也可能没有,但这是 OP 想要的。
  • 一个大的二进制块可以在 '\n' 上分割,一些指针的增量比我怀疑的多个 reallocs() reallocs 快得多。但取决于有多少行。
【解决方案4】:
  1. 如果文件很大,磁盘 I/O 将比内存管理昂贵得多。在分析之前担心 malloc/free 性能表明这是一个瓶颈是过早的优化。

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

【讨论】:

    【解决方案5】:

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

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

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

    【讨论】:

      【解决方案6】:
      1. 我认为最好分配 您需要的实际空间,以及 开销可能不会 重大。这既避免了 浪费空间和堆栈溢出

      2. 是的。虽然 IO 被缓存, 你在做不必要的系统调用 (打开和关闭)。使用 fseek 可能是SEEK_CURSEEK_SET

      【讨论】:

        【解决方案7】:

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

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

        2. 这可能会对性能造成很大影响。我强烈建议使用 fseek,但具体取决于您的算法。

        【讨论】:

          【解决方案8】:

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

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 2014-01-01
            • 2021-12-11
            • 1970-01-01
            • 2012-05-05
            • 2011-04-14
            • 2015-04-23
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多