没有完成端口的异步IO?

时间:2017-12-08 04:43:26

标签: c# asynchronous threadpool iocp

// 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
}
  • 说case1相当于Task.Run(() => file.Read)是否安全?换句话说,之前阻塞了线程池中的线程 read返回,而case2没有阻塞线程,如中所述 这篇文章:"There is no thread"
  • 何时使用case1(似乎是由...引入的默认方式) Microsoft Doc)over case2。我在服务器端做了一些工作,case2可能会为传入的请求提供更多备用线程吗?
  • 这只发生在文件上吗?我测试了httpClient().GetAsync()默认情况下它使用异步IO线程,但是可能有GetAsync()分离另一个线程的实现?

1 个答案:

答案 0 :(得分:2)

您的大部分问题似乎都可以通过查看源代码来解答:

  

•说case1相当于Task.Run(()=> file.Read)是否安全?换句话说,线程池中的线程在读取返回之前被阻塞,而case2没有阻塞线程,如本文所述:"没有线程"。

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;
}

虽然我全心全意地同意"没有线索"文章,重要的是要避免过于字面意思。 IOCP比将线程专用于单个操作更有效,但它仍然涉及一些线程。它只是可以使用更小的线程池,任何给定的线程都能够响应大量操作的完成。

  

•何时使用case1(似乎是Microsoft Doc引入的默认方式)而不是case2。我在服务器端做了一些工作,case2可能会为传入请求提供更多备用线程吗?

这个问题实在太宽泛了,主要是基于意见的。但我认为你应该总是使用FileOptions.Asynchronous来处理任何重要的文件I / O.如果由于某种原因你决定放弃并且仍然使用File.OpenRead(),那么你就不应该费心去使用任何异步调用。

对于执行非常简单的同步I / O的短程序,

File.OpenRead()非常方便。但是,如果您打算在File.OpenRead()对象上调用异步方法(例如FileStreamReadAsync()等,则永远不会使用BeginRead() )。如果代码以异步方式运行非常重要,那么它的重要性足以确保它使用Windows中的高效异步功能实际执行此操作。

  

•这只发生在文件中吗?我针对httpClient()进行了测试。默认情况下,GetAsync()它使用异步IO线程,但是可能有GetAsync()分离另一个线程的实现?

您所询问的行为显然是针对您的代码示例中显示的唯一差异:使用File.Open()(没有通过FileOptions.Asynchronous)并使用带有FileStream选项的FileOptions.Asynchronous构造函数。因此,询问这是否只发生在文件中并不是真的有意义。根据定义,File.Open()方法和FileStream对象仅适用于文件

那就是说,如果你要找到一个具有类似选项的不同类(即启用异步I / O),它肯定会完全相同(即没有启用选项就不使用IOCP),事实上是像HttpClientNetworkStream构建在Socket类之上,没有这样的选项,异步操作将通过该类的异步I /的实现O,总是使用IOCP。

所以,不......你不会在HttpClient类中找到一个禁止使用IOCP进行异步操作的选项。

当然,您总是可以自己包装同步调用,使用主线程池而不是IOCP线程池,然后就像非异步FileStream对象上的异步调用一样。 / p>