我正在用C语言编写一个批量ID3标签编辑器。ID3标签通常位于mp3编码文件的开头,尽管较旧的(版本1)标签位于末尾。该应用程序被设计为从命令行接受目录和帧ID列表,然后递归目录结构,更新它找到的所有ID3标签。用户还可以选择移除所有较旧的(版本1)标签。另一种选择是简单地显示当前标签,而不执行更新。该目录可能包含2个文件或200万个文件。如果用户想要更新文件,我计划将整个文件加载到内存中,执行更新,然后保存(文件也可以重命名)。但是,如果用户只想打印当前的ID3标记,那么加载整个文件就显得有些多余了。毕竟,文件大小可能是200mb。
我通读了这个帖子,很有洞察力- mmap() vs. reading blocks
所以我的问题是,最有效的方法是什么-- read()、mmap()还是某种组合?欢迎您的设计创意。
编辑:据我所知,mmap本质上是将文件加载到内存中,委托给虚拟内存子系统。在我看来,VMM在大多数系统上都是高度优化的,因为它对系统性能至关重要。
发布于 2011-04-08 09:56:56
这真的取决于你想要做什么。如果你所需要做的就是跳到一个已知的偏移量并读出一个小标签,read()可能会更快(mmap()必须做一些相当复杂的内部计算)。但是,如果您计划复制出所有200mb的MP3,或者扫描它以查找可能出现在未知偏移量处的标签,那么mmap()可能是一种更快的方法。
例如,如果需要将整个文件向下移动几百个字节以插入ID3标记,一种简单的方法是使用ftruncate()展开文件,映射文件,然后将内容向下映射一点。然而,如果你的程序在运行过程中崩溃,这将会破坏文件。您还可以将文件的内容复制到新文件中-这是mmap()真正发挥作用的另一个地方;您可以简单地mmap()旧文件,然后使用单个write()将其所有数据复制到新文件中。
简而言之,如果您正在进行大量的IO,就总的传输字节而言,mmap()是非常好的;这是因为它减少了所需的副本数量,并且可以显著减少读取缓存数据所需的内核条目的数量。但是,mmap()至少需要两次进入内核的过程(如果在完成后清除了映射,则需要三次)。并执行一些复杂的内部内核计算,因此固定开销可能很高。
另一方面,read()涉及额外的内存到内存的复制,因此对于大型I/O操作可能效率较低,但很简单,因此固定开销相对较低。简而言之,对大型批量I/O使用mmap(),对一次性小型I/O使用read()或pread()。
发布于 2011-04-08 09:51:52
不要费心使用mmap,除非你的代码是受CPU限制的,特别是由于大量的小读写。mmap听起来可能不错,但它并不是很棒,为什么不是每个人都在使用它看起来像这样的替代方案。
假设您正在递归遍历可能很大的目录结构,那么您的瓶颈将是目录IO和并发。mmap是帮不上忙的。
Update0
阅读链接到的问题可以找到支持我的经验的答案:
发布于 2011-04-08 07:09:47
如果您通常不打算流式传输文件,然后处理它,而是跳来跳去(比如读取前面的标签,然后跳到末尾,等等)然后我会使用mmap,因为你的代码会更整洁,更容易维护,把文件当做一个大的缓冲区,而不必自己去管理缓冲和分页。
如前所述,如果您正在处理大量数据,那么磁盘I/O很可能会主导您的处理。mmap可能比读取更快,但对于合理的实现,它可能不会那么快,特别是在当今的硬件上,这些硬件越来越快,而磁盘驱动器多年来一直停留在7200和10000 RPM。
因此,使用mmap并使您的代码简单整洁。
https://stackoverflow.com/questions/5588605
复制相似问题