【问题标题】:Should I call fopen - fclose every fwrite action我应该调用 fopen - fclose 每个 fwrite 操作吗
【发布时间】:2016-06-30 09:10:46
【问题描述】:

我正在数据库系统中制作类似于commit log 的东西。该系统能够处理约 20,000 个事件/秒。每个事件占用约 16 个字节。粗略地说,系统将以 ~312.5 kB / 秒的速度写入commit log。每个commit log 文件最多包含500,000 个事件。

我有一个问题:我应该为每个事件调用fopen - fwrite - fclose,还是应该在创建新文件时调用一次fopen,然后是一系列fwrite,最后是fclose

【问题讨论】:

  • fopen, fclose 非常昂贵,因此不建议每次写入。但是,为了保持崩溃一致性,您可能需要定期刷新文件。
  • @user3386109 不幸的是,没有标准的方法可以“防止您在异常终止时丢失超过 1 个事件”。例如,如果断电,则驱动控制器已缓冲但尚未写入盘片的任何数据都将丢失。没有标准方法可以强制驱动控制器将其缓冲区的内容写入盘片。 fflush 不处理这个问题。 fflush 处理强制操作系统将未写入的数据发送到驱动器控制器。

标签: c file-io fopen file-handling fclose


【解决方案1】:

在这种情况下,最好恢复到 open/write/close 并完全摆脱 C 缓冲输出。日志文件通常包含大量几乎相同(按大小)的写入,并且不会真正从 C 缓冲中获得太多收益。低级别、无缓冲的 I/O 也可以让您不必调用 fflush(),并且可以保证将每个日志条目都写入原子实体。

鉴于您提到的卷,您可能仍然不应该在写入之间关闭并重新打开文件。

【讨论】:

  • 我正在检查 Windows 上的低级文件 IO API。看来我仍然必须调用 _commit 来强制刷新到磁盘。 Posix 上有没有类似的东西?
  • _commit() 等效的 POSIX 可能是 fsync()。而且我可能都不会使用。这在一定程度上取决于您正在记录的 what。如果您的日志文件旨在用于事后分析或恢复计算机应用程序,那么尽可能多地保护日志条目可能是有意义的。但是,如果您要记录一些 external 事件,我不会走那条路。
【解决方案2】:

fopen/fwrite/fclose 每秒 20k 次看起来相当昂贵。 考虑调用 fflush 作为替代方法。

如果您希望使用它来记录数据库事务以进行可能的恢复,您可能需要重新考虑它。 f 系列函数使用缓冲,因此在发生崩溃时,最终缓冲区可能会或可能不会真正进入磁盘。

【讨论】:

  • 是的。我打算使用commit logs 进行恢复。您能给我一些替代方案的建议吗?
  • 使用支持事务的数据库。
【解决方案3】:

您没有义务,不...事实上,按照EvilTeach's answer 的建议,致电fflush 会更好。

但是,更好的是,如果您可以避免调用 fflush,那将是理想的,因为 C 标准库可能(可能会)实现特定于系统的缓存以将较小的物理写入合并到较大的物理写入中,从而使您每次写入 20k第二个更优化。

按照您的建议调用 fopen/fwrite/fclose 或按照 EvilTeach 的建议调用 fflush 会避开缓存,这可能会降低性能。

【讨论】:

    猜你喜欢
    • 2015-12-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-01-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-06-04
    相关资源
    最近更新 更多