在本地复制大文件的最快方法

时间:2018-03-29 01:29:37

标签: linux file-io operating-system copy filesystems

我在接受采访时被问到这个问题。

我说让我们使用cp。然后我被要求模仿实现cp本身。

所以我认为没问题,让我们打开文件,逐个阅读并将其写入另一个文件。

然后我被要求进一步优化它。我想让我们做大块的阅读和写这些块。关于什么是好的块大小,我没有一个很好的答案。请帮帮我。

然后我被要求进一步优化。我想可能是我们可以并行读取不同的线程并将其并行写入。

但是我很快意识到并行读取是正常的但是写入不会并行工作(我没有锁定),因为来自一个线程的数据可能会覆盖其他线程。

所以我认为没问题,让我们并行读取,将它放入队列然后单个线程将其从队列中取出并逐个写入文件。

这甚至可以提高性能吗? (我的意思是不适用于小文件。对于大文件来说,它会有更多的开销)

此外,是否有像操作系统技巧,我可以将两个文件指向磁盘中的相同数据?我的意思是我知道有符号链接但除此之外?

2 个答案:

答案 0 :(得分:1)

"复制文件的最快方法"将依赖于系统 - 从存储介质到CPU的所有方式。最可能的瓶颈将是存储介质 - 但它并非必须如此。想象一下,高端存储可以更快地移动数据,而不是系统可以创建物理页面映射来将数据读入......

一般来说,移动大量数据的最快方法是尽可能少地复制它,并避免任何额外的操作,特别是S-L-O-W,例如物理磁头搜索。

因此,对于常见的单旋转磁盘工作站/台式机/笔记本电脑系统上的本地副本,最重要的是尽量减少物理磁盘搜索。这意味着以大块(例如1 MB)读取和写入单线程,这样系统就可以进行任何优化,例如预读或写入合并。

这可能会使您获得95%甚至更高的系统最大复制性能。即使标准C缓冲fopen() / fread() / fwrite()也可能获得至少80-90%的最佳性能。

您可以通过几种方式获得最后几个百分点。首先,将IO块大小与文件系统块大小的多个匹配,以便始终从文件系统中读取完整块。其次,您可以使用直接IO来绕过通过页面缓存复制数据。转到磁盘 - >用户空间或用户空间 - >磁盘比转到磁盘 - >页面缓存 - >用户空间和用户空间 - >页面缓存 - >磁盘更快,但对于单次旋转 - 磁盘副本,如果它甚至可以测量,那就不重要了。

您可以使用各种dd选项来测试复制此类文件。尝试使用directnotrunc

您还可以尝试使用sendfile()来避免将数据完全复制到用户空间。根据实施情况,这可能比使用直接IO更快。

预分配目标文件可能会也可能不会提高复制性能 - 这取决于文件系统。但是,如果文件系统不支持稀疏文件,那么将文件预分配到特定长度可能非常非常慢。

你可以做的就是大幅度提高副本从同一个旋转的物理磁盘上的性能 - 那些磁头会跳舞,这需要时间。

SSD更容易 - 获得最大IO速率,只需通过多个线程使用并行IO。但同样,"正常" IO可能会达到最大值的80-90%。

对于其他类型的存储系统(例如大型RAID阵列和/或可跨多个底层存储设备对单个文件进行条带化的复杂文件系统),事情变得更加有趣和复杂,从而优化了IO性能。在这样的系统上最大化IO涉及将软件的IO模式与存储的特征相匹配,这可能非常复杂。

最后,最大化IO率的一个重要部分就是不会做太大的事情。将物理磁盘拖动到几KB /秒的IO速率非常容易 - 从/向整个磁盘上的随机位置读/写小块。如果您的写入过程将16字节块丢弃到随机位置,则磁盘将花费几乎所有时间进行搜索,并且在执行此操作时根本不会移动大量数据。

事实上,不是"自杀" IO模式不好比花费大量精力试图在最佳情况下更快地获得4或5个百分点更为重要。

因为如果IO是一个简单系统的瓶颈,那就去购买更快的磁盘。

答案 1 :(得分:0)

  

但是我很快意识到并行读取是正常的但是写入不会并行工作(我没有锁定),因为来自一个线程的数据可能会覆盖其他线程。

多线程通常不会加速像这样的进程。您可能获得的任何性能优势都可能被同步开销消除。

  

所以我认为没问题,让我们并行读取,将它放入队列然后单个线程将其从队列中取出并逐个写入文件。

这只会在支持异步I / O的系统上发挥优势。

要获得最大速度,您希望以缓冲区大小写入,该缓冲区大小是磁盘集群因子的增量(假设是硬文件系统)。这可以在允许排队异步I / O的系统上加速(例如,Windoze)。

您还希望创建输出文件,其初始大小与输入文件相同。这样你的写操作就不必扩展文件。

可能最快的文件复制可能是内存映射输入和输出文件并进行内存复制。这在将映射文件视为页面文件的系统中尤其有效。