async / await并打开FileStream?

在尝试确定我是否正确使用ReadAsyncCopyToAsyncStream方法时,我遇到了以下问题: C#4.5文件读取性能sync vs async

在这个问题中,我在接受的答案中阅读了以下内容:

最值得注意的是,您的“异步”测试不使用异步I / O; 对于文件流, 您必须将它们显式地打开为异步,否则您只是在后台线程上执行同步操作。

在他的异步IO代码中,他使用以下命令“异步”打开FileStream

 var file = new FileStream(filename, FileMode.Open, FileAccess.Read, FileShare.Read, 4096, true) 

所以我想知道你是否打算使用像CopyToAsync这样的方法,你是否应该打开如上所示的底层FileStream ?而不是像下面那样做一些简单的事情:

 File.Open(filename, FileMode.Open) 

以下是CopyToAsync实际文档中的CopyToAsync演示如何打开底层FileStream : https : CopyToAsync

如果打开底层FileStream方式useAsync ,那么FileStream构造函数的useAsync参数有什么作用?

所以我想知道你是否打算使用像CopyToAsync这样的方法是否应该打开底层的FileStream,如上所示?

是。 原因主要是历史性的。

首先,在Windows上, 如果要对它们执行异步( OVERLAPPED )操作,则必须使用异步标志显式打开/创建HANDLE (包括文件句柄) 。

但是, 旧的Windows 95/98 / ME系列支持串行端口和IOCTL(设备驱动程序)句柄上的异步操作 。 该平台线上不支持磁盘文件上的异步I / O. 原始的.NET 确实支持98 / ME ,因此原始的FileStream只使用了同步I / O. 我认为 (但不是绝对肯定)Win98 / ME上的APM方法 (如FileStream.BeginRead )可能只是使用所谓的“异步委托” (它只是在线程池上执行类似FileStream.Read的同步方法)来实现的。线)。

因此,这是文件流句柄默认情况下使用异步标志打开的历史原因。

这是CopyToAsync的实际文档中的示例如何演示

不幸的是,许多MSDN示例质量相当差。 如果你从“这是一个如何调用这种特定方法的例子”的角度来看待它们,那就没关系了,但从“这是使用这种方法的生产质量代码的例子”的角度来看,它们并不是那么好。

所以我想知道你是否打算使用像CopyToAsync这样的方法是否应该打开如上所示的底层FileStream,而不是像File.Open那样做一些简单的事情?

我用ILSpy反编译并查看File.Open

 public static FileStream Open(string path, FileMode mode) { return File.Open(path, mode, (mode == FileMode.Append) ? FileAccess.Write : FileAccess.ReadWrite, FileShare.None); } 

这称之为:

 public static FileStream Open(string path, FileMode mode, FileAccess access, FileShare share) { return new FileStream(path, mode, access, share); } 

此特定的FileStream构造函数为useAsync参数传递false 。 所以,是的,似乎很重要。 但是,您仍然可以调用async API,它仍然可以按预期工作。

正如Hans Passant所说:

然后,基础CreateFile()调用使用FILE_FLAG_OVERLAPPED选项。 这实现了重叠I / O ,这是一种在winapi级别启用异步读写的机制。

FileStream类具有_isAsync bool,它表示“如果此平台不支持异步IO,或者未使用FileOptions.Asynchronous打开此FileStream。”。

同样,您仍然可以根据需要获得表示异步操作的Task

MSDN网站说:

useAsync

类型: System.Boolean

指定是使用异步I / O还是同步I / O. 但请注意,底层操作系统可能不支持异步I / O,因此在指定true ,可能会根据平台同步打开句柄。 异步打开时, BeginRead和BeginWrite方法在大型读取或写入时执行得更好,但对于小型读取或写入,它们可能要慢得多。 如果应用程序旨在利用异步I / O,请将useAsync参数设置为true 。 正确使用异步I / O可以将应用程序的速度提高10倍,但在不重新设计异步I / O应用程序的情况下使用它可以将性能降低10倍。