23

这不是一个纯粹的编程问题,但是它会影响使用 fseek() 的程序的性能,因此了解它的工作原理很重要。一点免责声明,以免它被关闭。

我想知道在文件中间插入数据的效率如何。假设我有一个包含 1MB 数据的文件,然后我在 512KB 偏移处插入了一些东西。与在文件末尾附加我的数据相比,效率如何?为了使示例完整,假设我想插入 16KB 的数据。

我知道答案因文件系统而异,但是我假设常见文件系统中使用的技术非常相似,我只想了解它的正确概念。

4

6 回答 6

5

(免责声明:我只想为这个有趣的讨论添加一些提示)恕我直言,有一些事情需要考虑:

1) fseek 不是一个主要的系统服务,而是一个库函数。为了评估它的性能,我们必须考虑文件流库是如何实现的。一般来说,文件I/O库在用户空间增加了一层缓冲,所以如果目标位置在当前缓冲区之内或之外,fseek的性能可能会有很大的不同。此外,I/O 库使用的系统服务可能会有很大差异。即在某些系统上,如果可能,该库会广泛使用文件内存映射。

2)正如你所说,不同的文件系统可能以非常不同的方式表现。特别是,我希望事务文件系统必须做一些非常聪明且可能代价高昂的事情,以准备好在文件中间可能回滚中止的写入操作。

3) 现代操作系统具有非常激进的缓存算法。“fseeked”文件可能已经存在于缓存中,因此操作变得更快。但是如果其他进程产生的整体文件系统活动变得重要,它们可能会降级很多。

任何意见?

于 2010-03-13T16:23:15.420 回答
4

让我们以 ext2 FS 和 Linux OS 为例。我认为插入和追加之间不会有显着的性能差异。在这两种情况下,必须读取文件节点和偏移表,将相关磁盘扇区映射到内存中,更新数据,并在稍后将数据写回磁盘。在此示例中,会产生很大性能差异的是在访问文件的某些部分时具有良好的时间和空间局部性,因为这将减少加载/存储组合的数量。

正如先前的答案所说,如果您处理的数据写入恰好是 FS 块大小的倍数,您可能能够加快这两个操作,在这种情况下,您可以跳过加载阶段,只需将新块插入文件 inode 数据结构中。这不切实际,因为您需要对 FS 驱动程序进行低级别访问,并且使用它会非常受限制且不可移植。

于 2010-03-13T16:09:31.940 回答
3

fseek(...)是库调用,而不是操作系统系统调用。运行时库负责处理对操作系统进行系统调用所涉及的实际开销,从技术上讲,fseek 是间接调用系统,但实际上并非如此(这在库调用和系统调用之间的区别)。fseek(...)是一个标准的输入输出函数,不管底层系统如何......然而......这是一个很大......

操作系统很可能已将文件缓存在其内核内存中,即磁盘上存储 1 和 0 的位置的直接偏移量,它很可能是通过操作系统的内核层,内核中的最顶层,它将拥有文件组成的快照,即数据而不管它包含什么(它不关心任何一种方式,只要指向该偏移量的磁盘结构的“指针”到磁盘上的 lcoation 是有效的!)...

发生时fseek(..),会有很多开销,间接地,内核委派了从磁盘读取的任务,这取决于文件的碎片程度,理论上可能是“到处都是”,这可能是就必须从用户空间的角度来看,即 C 代码执行的操作而言fseek(...),它可能会分散在各处以将数据收集到“数据的一个连续视图”中,此后,插入到文件的中间,(记住在这个阶段,内核必须将位置/偏移量调整到数据的实际磁盘盘片中)将被认为比附加到文件末尾要慢。

原因很简单,内核“知道”最后一个偏移量是什么,只需擦除 EOF 标记并插入更多数据,在幕后,内核必须为磁盘缓冲区分配另一块内存数据追加完成后,调整到 EOF 标记后磁盘位置的偏移量。

于 2010-03-13T16:39:08.323 回答
2

我在 Solaris 上所做的一个观察fseek是,每次调用它都会重置FILE. 下一次读取将始终读取一个完整的块(默认为 8K)。因此,如果您通过少量读取进行大量随机访问,那么最好不要缓冲(setvbuf使用NULL缓冲区),甚至使用直接系统调用(lseek+read甚至更好pread,只有 1 个系统调用而不是 2 个)。我想这种行为在其他操作系统上会类似。

于 2010-08-29T18:48:11.147 回答
1

只有当数据大小是 FS 扇区的倍数时,您才能有效地将数据插入文件中间,但操作系统不提供此类功能,因此您必须使用 FS 驱动程序的低级接口。

于 2010-03-13T16:03:39.193 回答
1

在文件中间插入数据比追加到末尾效率低,因为插入时必须将数据移动到插入点之后,以便为插入的数据腾出空间。移动这些数据将涉及从磁盘读取它们,写入要插入的数据,然后在插入数据之后写入旧数据。所以你在插入时至少有一个额外的读写。

于 2010-03-13T16:31:25.057 回答