【问题标题】:Benefits of saving multiple files async异步保存多个文件的好处
【发布时间】:2018-07-12 11:47:11
【问题描述】:

我正在控制器上编写一个将文件保存到磁盘的操作。在 .Net Core 2.0 上

我看到了一些这样保存文件的代码。

foreach (var formFile in files)
{
    if (formFile.Length > 0)
    {
        using (var stream = new FileStream(filePath, FileMode.Create))
        {
            await formFile.CopyToAsync(stream);
        }
    }
}

这是异步但按顺序保存文件。所以我决定写得有点不同

var fileTasks = files.Where(f => f.Length > 0).Select(f => this.SaveFile(f, BASE_PATH));
await Task.WhenAll(fileTasks);

protected async Task SaveFile(IFormFile file, string basePath)
{
    var fileName = Path.GetTempFileName();
    var filePath = Path.Combine(basePath, fileName);

    using (var stream = new FileStream(filePath, FileMode.Create))
    {
        await file.CopyToAsync(stream);
    }
}

假设我将它们全部保存到同一个驱动器,这样做有什么好处吗?

我知道我不会阻塞任何线程,但是在 Disc 上还会有瓶颈吗?或者现代计算机可以一次保存多个文件吗?

【问题讨论】:

  • 现代磁盘驱动器一次仍然只写入磁盘的一部分。
  • @Plutonix 这包括 SSD 吗?
  • 不知道,但测试和基准测试肯定很简单。
  • 谢谢,如果您想将此作为答案发布,我会接受。
  • 不是答案,只是对race them的建议

标签: c# multithreading asynchronous io .net-core


【解决方案1】:

Disc 还会有瓶颈吗?或者现代计算机可以一次保存多个文件吗?

是的,是的。磁盘,比计算机的其他部分慢几个数量级,将永远是一个瓶颈。但是,虽然不可能一次在磁盘上写入比写入磁头更多的位置(旋转介质磁盘几乎都有多个写入磁头,因为几乎所有此类磁盘上都有多个盘片和盘片面),当然现代计算机(甚至不那么现代的计算机)可以一次跟踪多个文件的 I/O。

对更广泛问题的简短回答:确定任何性能问题的唯一方法是对其进行测试。这里没有人可以预测结果会是什么。即使对于相对简单的 CPU 密集型问题也是如此,当您处理诸如将数据写入存储设备这样复杂的事情时,这一点更为重要。

即使您发现现在可以使文件 I/O 更快,这种努力在未来可能仍然存在,也可能不存在。甚至有可能您的代码比更简单的实现


更长的版本……

影响实际性能的问题包括:

  • 驱动器类型。具有旋转介质的传统硬盘通常比 SSD 慢得多,但每种类型的驱动器都有其特定的性能特征。
  • 驱动器配置。不同的制造商提供具有不同磁盘 RPM(用于旋转驱动器)、不同控制器、不同缓存大小和类型以及对磁盘协议的不同支持的驱动器。一个逻辑驱动器实际上可能是多个物理驱动器(例如 RAID),即使在一个驱动器内,存储也可以进行不同的配置:旋转介质驱动器可以有不同数量的盘片用于给定数量的存储,而 SSD 可以使用多种存储技术和安排(即单级与多级单元,具有不同的块大小和布局。这远不是磁盘驱动器中可能看到的变化类型的详尽列表。
  • 文件系统。甚至 Windows 也支持范围广泛的文件系统,而其他操作系统也有更广泛的选择。每个文件系统都有其擅长和不擅长的特定方面,性能将取决于文件访问方式的确切性质。
  • 驱动软件。驱动器大多使用标准化的 API,通常操作系统中的基本驱动程序用于所有类型的驱动器。但也有例外。
  • 操作系统版本和配置。不同版本的 Windows 或任何其他操作系统在处理磁盘 I/O 方面有细微的不同。即使在给定版本的操作系统中,给定驱动器的配置也可能不同,并带有缓存选项。

可以进行一些概括,但对于每一个真正的概括,都会有一个例外。墨菲定律让我们得出结论,如果您忽略对实现的实际测试,您最终会成为例外。

话虽如此,可能同时写入多个文件可以提高吞吐量,至少对于具有旋转介质的磁盘而言。为什么?

虽然@Plutonix 的上述评论是正确的,但它确实掩盖了磁盘控制器将尽可能优化写入这一事实。一次将多个写入排队(无论是由于多个文件还是单个文件散布在磁盘周围)允许磁盘控制器利用磁盘的当前位置。

例如,假设您要一次写入一个文件块。你写了一个块,当你发现它被写了,你再写一个。好吧,当您开始写入下一个块时,磁盘已经移动,所以现在您需要等待正确的位置回到写入头,然后才能完成下一次写入。

那么,如果您一次将两个块交给操作系统会怎样?现在,磁盘控制器可以被告知两个块,如果一个块可以立即写入另一个块,那么它就可以被写入了。无需等待磁盘再次旋转。

您一次可以移交的块越多,磁盘控制器一次可以看到的写入越多,它能够在磁盘在写入头下旋转时连续写入块的可能性就越大,而不必暂停并等待正确的位置回来。

那么,为什么不总是这样写文件呢?嗯,最大的原因是我们通常不需要那么快地写入数据。文件 I/O 需要 500 毫秒而不是 50 毫秒,不会给用户带来不便。

另外,它显着增加了代码的复杂性。

此外,编程框架、操作系统、文件系统和磁盘控制器都具有提供大部分或全部相同好处的功能,而无需程序本身更加努力地工作。在磁盘 I/O 的每一层进行缓冲意味着当您的程序写入文件时,它认为写入速度非常快,但所发生的只是所有数据都被磁盘 I/O 管道中的一个或多个层隐藏起来, 允许这些层一次向磁盘提供足够的数据,以进行优化,包括定时写入,以便对您的程序透明地完成盘片位置。

通常——我猜几乎是所有时间——如果你的程序只是以足够快的速度顺序流式传输数据,即使没有任何并发​​,磁盘仍然可以保持高效率,因为缓冲区足够大确保对于写入头下的任何可写块,都有一个数据块可以写入。

当然,SSD 显着改变了分析。物理介质上的延迟不再是问题,但构建 SSD 的方法有很多,每种方法都有不同的性能特征。最重要的是,SSD 的技术仍在迅速变化。设计和制造 SSD、他们的控制器,甚至是使用它们的操作系统的人员,都在努力确保即使是简单的程序也能高效运行。

因此,一般而言,只需天真地编写代码即可。这样做的工作量要少得多,而且在大多数情况下它也能正常工作。如果您决定测量性能,并发现可以通过异步写入多个文件来提高磁盘 I/O 的工作效率,请计划随着时间的推移定期重新检查您的结果。更改磁盘技术很容易使您的优化无效,甚至适得其反。


相关阅读:

How to handle large numbers of concurrent disk write requests as efficiently as possible
outputing dictionary optimally
Performance creating multiple small files
What is the maximum number of simultaneous I/O operations in .net 4.5?

【讨论】:

  • 非常感谢您抽出宝贵时间来解释这一点
猜你喜欢
  • 2019-01-22
  • 1970-01-01
  • 2016-11-17
  • 2019-08-01
  • 2021-12-13
  • 1970-01-01
  • 2013-05-10
  • 2014-10-24
  • 1970-01-01
相关资源
最近更新 更多