为什么单个大文件比总体积相同的多个小文件复制起来要快很多?
上层来说,影响性能的通常是io。然后是cache。顺序读写对cache有利。假设你是操作系统开发者,设身处地去想就很容易理解了。比如你知道读硬盘时寻道是很慢的,所以你的读文件操作的实现是预先往前读多比如几百k(虽然用户指定的是几十k),到内存或者硬件(硬盘自带的)cache,如果刚好用户也是想读下几百k,那这时你从内存提交到用户,不用硬盘的机械设施去寻址读入,显然速度就高了……这只是通俗不严谨的例子……(当然小文件假定随机的情况下,他们不是连续存储的;驱动/操作系统或运行时/api的开发者也是基于同样假设去优化;非要针对连续存储的n个小文件来实现系统,会比同样总大小的一个文件慢吗?当然可以有一样快的实现方法!)这里面其实有很多层抽象层次和策略,要对体系结构和操作系统有一定思想性的了解才有体会。但再多优化也不外如是基本原理:分层体系,cache和预测策略。举一反三地说,所有硬件访问(存储io,图形硬件io,甚至cpu指令流水等优化机制)都基于这种基本思想。
并非一定快。但单的大文件复制速度快的概率大。假设为无故障机械硬盘。硬盘操作两种文件速度比较。1.单个大文件在硬盘上物理地址连续分布的概率比多个小文件在硬盘上物理地址连续分布的概率大。对于机械硬盘,连续分布地址上读取速度较快。假如在有10个房间各有一个球,按照1、2、3…10的顺序取球比1、3、5、2、4、8…这样的顺序取球快。2.第二个原因是我猜的,揣测一下,复制的时候要不要处理数据呢?假如每个文件都有加密/压缩/校验的话,也许大文件只需一次算法,小文件要进行1024种算法。当然,这是一部分原因
因为复制文件的时候所作的事情不仅仅是复制数据,一般还有一个类似于初始化的过程,而这个初始化的过程所需的时间又和文件大小没什么关系,所以,当你复制很多小文件的时候,这个初始化过程所需的总时间可能会很多,多到和复制数据所需的时间差不多,这时你就觉得异常了。由于不同的文件系统的这个初始化过程的细节是不一样的,所以这里不讨论细节。下面打个比方吧。小学老师布置了一份作业,抄写某课文10次。一般的同学都会找来作业本,削好铅笔,打开课本找到那篇课文,开始抄写,直到抄完10次。但是,有一个比较笨的同学,一开始他的做法和大家一样,但是每抄完一次,他就重新把作业本、铅笔和课本放回原处,然后,重新拿来作业本,削铅笔,打开课本找到课文,开始抄写。这个比较笨的同学就是让你感觉复制小文件很慢的那种文件系统。
技术方面,就说说机械硬盘吧。这东西的读写性能是很随机的一个事情,除了和是否是顺序读写有关之外,和寻道有关系,和存在里圈还是外圈也有关系,实际表现往往呈现很大的随机性。不信可以自己写个脚本测一测读写文件的速度,看在文件系统层能不能把读写时间浮动控制得很小。我当初上课做硬盘性能测量的时候都是要固定读写硬盘的某个物理位置才能得到比较稳定的数据。所以,问题里的这个现象,如果不把条件说清楚,别说解释为什么,连重复都很难。比如,我自己在LinuxExt4的机械硬盘上就无法重复这个现象。我在自己的home目录下拷贝1G文件的时间总是比1024个1M文件要慢若干秒。为什么会这样呢?可能的因素很多很复杂。最大的原因可能是因为Ext4是存Journal的,所以1024个小文件的很大部分还都在Journal里操作,离得很近,寻道很快,甚至是在同一个block里。而那个1G的文件却不会全存在Journal里,所以要反复在不同的位置读写硬盘,所以相对慢一点。如果是在Windows的FAT32下恐怕就是另一回事了,因为Journal没了。如果复制的源位置和目标位置是两块不同的硬盘又是另一回事了,因为现在读写是独立的两个寻道了。如果硬盘不是机械硬盘而是SSD就又是另一回事了,因为寻道没了。
其实这个事情,简单的说,就是Windows的文件系统对小文件的优化不到位。原因可能有很多,大家很多人都已经说了,我就不重复。ext4在这个问题上确实有明显优势,但要认真去研究这个问题其实很难的,原因是:在Linux这样的我们能看到源代码并进行分析的系统中,其实这个现象并不特别明显。从纯学术的角度来看,无法推断问题发生的原因。在Windows系统中虽然很容易重现这个现象,但我们无法分析其原因,因为没有源代码。
磁盘以扇区为单位,所以存在磁盘上的文件具体在那些扇区上需要记录下来,这个信息就记录在这个文件对应的inode中。当然,inode本身也要存放在磁盘上。所以当读取一个文件的时候,首先要读取到这个文件inode(这是一次磁盘IO),从中得知文件内容在哪些扇区中,然后读取这些扇区的内容。所以,泛泛而谈的话,时间差距应该主要来源于inode操作。
1、小文件导致IO次数增多,磁盘IO次数本身就有瓶颈;2、小文件实际写入的内容也更多(这里我没包括索引项,实际索引项也很多,但不好表达);3、小文件导致CPU负担更重,需要匹配更多的信息。以上三点造成了小文件复制比大文件慢,所有操作系统的所有文件系统基本上都有以上三个原因。如果题主有兴趣,可以去看Linux源码,Windows的源码下载一个WINDDK可以看到FAT驱动源码。
复制一个文件需要做的有1-3步:1、在目标位置创建对应的文件名项,因为文件名也是要保存在磁盘上的;2、如果文件有内容,把文件内容写入磁盘,并按照块对齐(512字节-64K不等)3、如果文件有内容,在一个特定的位置把文件内容的块的信息记录下来,标记这些块属于这个文件并且是被使用了。因为题主问的是1M的文件,所以这三步都是需要的。对于1G的文件,需要的也是这三步,对于1024个1M的文件,需要的是1024×3步。对于磁盘设备有IOps的概念,就是每秒能执行的I/O次数,对于复制1024个1M文件来说,那么至少需要1024*3次I/O,对于1G的文件来说,至少需要3次。所以从次数来说,复制小文件越多,磁盘读写次数越多,虽然有cache等一系列优化的机制,但整体次数还是要高很多的。并且,磁盘写1字节,和写512字节(一个扇区)的代价是相同的,虽然写入文件名短,但仍然需要写入512字节(一个扇区)。因此写1G文件就至少要比写1024*1M文件多写512K这么多数据。
回答请先登录