没有完成端口的异步 IO?

Async IO without completion port?

// 1- 
using(FileStream file = File.Open("ConfusedDev", FileMode.Open)) {
    await file.ReadAsync(buffer, 0, 1024);
    Thread.Sleep(Timeout.Infinite); // threadpool shows 1 worker thread in use
}

// 2- 
using(FileStream file = new FileStream("ConfusedDev", FileMode.Open, FileAccess.Read, FileShare.Read, 1024, FileOptions.Asynchronous)) {
    await file.ReadAsync(buffer, 0, 1024);
    Thread.Sleep(Timeout.Infinite); // threadpool shows 1 async IO thread in use
}

您的大部分问题似乎只需查看源代码即可得到解答:

• Is it safe to say that case1 is equivalent of Task.Run(() => file.Read)? In other words, a thread in threadpool is blocked before read returns whereas case2 has no blocking thread as mentioned in this post: "There is no thread".

File.OpenRead() 不会将 FileOptions.Asynchronous 传递给 FileStream 构造函数,因此任何异步调用都是使用线程池中的阻塞 I/O 实现的。具体来说,对 ReadAsync() 的调用最终会调用 FileStream.BeginRead(),如果实例不是使用 FileOptions.Asynchronous 创建的,它会将读取委托给 the base class BeginRead(), which eventually executes this anonymous method as a task:

delegate
{
    // The ReadWriteTask stores all of the parameters to pass to Read.
    // As we're currently inside of it, we can get the current task
    // and grab the parameters from it.
    var thisTask = Task.InternalCurrent as ReadWriteTask;
    Contract.Assert(thisTask != null, "Inside ReadWriteTask, InternalCurrent should be the ReadWriteTask");

    // Do the Read and return the number of bytes read
    var bytesRead = thisTask._stream.Read(thisTask._buffer, thisTask._offset, thisTask._count);
    thisTask.ClearBeginState(); // just to help alleviate some memory pressure
    return bytesRead;
}

虽然我完全同意 "There is no thread" 文章,但重要的是要避免从字面上理解它。 IOCP 比将线程专用于单个操作更有效,但它仍然涉及一些 个线程。只是可以使用更小的线程池,并且任何给定的线程都能够响应更多操作的完成。

• When to use case1(seems to be the default way introduced by Microsoft Doc) over case2. I am doing some work on the server side, case2 probably give me more spare threads for incoming requests?

这个问题真的太宽泛了,而且主要是基于意见。但我认为您应该 始终 对任何重要文件 I/O 使用 FileOptions.Asynchronous。如果出于某种原因你决定放弃它并使用 File.OpenRead(),那么你不应该费心使用任何异步调用。

File.OpenRead() 对于做非常简单的同步 I/O 的短程序来说很方便也很好。但是你应该 永远不要 使用 File.OpenRead() 如果你打算然后调用 FileStream 对象上的异步方法(例如 ReadAsync(), BeginRead(), ETC。)。如果代码异步操作足够重要,那么使用 Windows.

中的高效异步功能来确保它确实这样做也很重要

• Does this only happen to files? I tested against httpClient().GetAsync() it uses async IO thread by default, but maybe there is implementation where GetAsync() spin off another thread?

显然,您所询问的行为特定于代码示例中显示的唯一区别:使用 File.Open()(未通过 FileOptions.Asynchronous)和使用 FileStream 构造函数与 FileOptions.Asynchronous 选项。所以问这是否只发生在文件上是没有意义的。 File.Open() 方法和 FileStream 对象根据定义仅适用于 文件 .

也就是说,如果您要找到一个具有相似选项的不同 class(即启用异步 I/O 或不启用),它肯定会以相同的方式工作(即不使用 IOCP 而不是选项已启用),实际上像 HttpClientNetworkStream 是建立在 Socket class 之上的,它没有这样的选项,异步操作将会继续通过 class 的异步实现 I/O,它始终使用 IOCP。

所以,不……您不会在 HttpClient class 中找到禁用 IOCP 进行异步操作的选项。

当然,您始终可以自己包装同步调用,使用主线程池而不是 IOCP 线程池,然后它的行为就像对非异步 FileStream 对象的异步调用一样.