Performance fseek()是如何在文件系统中实现的?

Performance fseek()是如何在文件系统中实现的?,performance,architecture,filesystems,fseek,Performance,Architecture,Filesystems,Fseek,这不是一个纯粹的编程问题,但是它会影响使用fseek()的程序的性能,因此了解它是如何工作的很重要。一点免责声明,这样它就不会被关闭 我想知道在文件中间插入数据是多么有效。假设我有一个1MB数据的文件,然后我在512KB的偏移量插入了一些东西。与将我的数据追加到文件末尾相比,效率有多高?为了使示例完整,假设我要插入16KB的数据 我知道答案因文件系统而异,然而,我假设常见文件系统中使用的技术非常相似,我只是想了解它的正确概念。只有当数据大小是FS扇区的倍数时,才能有效地将数据插入文件中间,但操作

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

我想知道在文件中间插入数据是多么有效。假设我有一个1MB数据的文件,然后我在512KB的偏移量插入了一些东西。与将我的数据追加到文件末尾相比,效率有多高?为了使示例完整,假设我要插入16KB的数据


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

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

让我们来看看以ext2fs和Linux操作系统为例。我认为insert和append之间不会有显著的性能差异。在这两种情况下,必须读取文件节点和偏移量表,将相关磁盘扇区映射到内存中,更新数据,并在稍后将数据写回磁盘。在本例中,当访问文件的某些部分时,会有很大的性能差异的是良好的时间和空间位置,因为这将减少加载/存储组合的数量

正如前面的回答所说,如果处理的数据写入是FS块大小的精确倍数,则可以加快这两个操作的速度,在这种情况下,您可以跳过加载阶段,只需将新块插入到文件inode datastructure中。这是不实际的,因为您需要对FS驱动程序进行低级别访问,并且使用它会受到很大的限制,而且不可移植。

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

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

2) 正如您所说,不同的文件系统可能会以非常不同的方式运行。特别是,我希望事务文件系统必须做一些非常聪明和昂贵的事情,以准备在文件中间进行一个中止的写操作的回滚。 3) 现代操作系统有非常积极的缓存算法。缓存中可能已经存在一个“fseeked”文件,因此操作速度会快得多。但是,如果其他进程产生的整个文件系统活动变得重要,它们可能会降低很多


任何注释?

< P>在文件中间插入数据比追加到末尾效率低,因为插入时必须在插入点之后移动数据,以便为插入的数据腾出空间。移动这些数据需要从磁盘读取数据,写入要插入的数据,然后在插入数据之后写入旧数据。因此,在插入时,您至少有一个额外的读写操作。

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

操作系统很可能将文件缓存在其内核内存中,也就是说,直接偏移到磁盘上存储1和0的位置,这是通过操作系统的内核层,很可能是内核中最顶层的一层,该层将有文件组成的快照,也就是说,数据与它所包含的内容无关(只要指向磁盘上LCO偏移量的磁盘结构的“指针”是有效的,这两种方式都无关紧要!)

当出现
fseek(…)
时,会有很多过度,间接地,内核委派了从磁盘读取的任务,这取决于文件的碎片程度,理论上可能是“到处都是”,从用户的角度来看,这可能是一个重大的过度,也就是说,C代码执行一个
fseek(…)
,它可能分散在所有地方,以将数据收集到“一个连续的数据视图”中,然后插入到文件的中间(请记住,在此阶段,内核必须调整数据在实际磁盘盘中的位置/偏移量)将被视为比追加到文件末尾慢


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

我对Solaris上的
fseek
做了一个观察,每次调用它都会重置
文件的读取缓冲区。然后,下一次读取将始终读取完整块(默认情况下为8K)。因此,如果您有大量随机访问和少量读取,最好使用无缓冲(
setvbuf
with
NULL
buffer)甚至使用直接系统