当我调用BeginXXX()时,CLR何时创建IO线程?

4
假设我调用HttpWebRequest.BeginGetRequestStream()方法。
我知道这个方法是异步的,当它完成时,应该调用回调方法。
我非常确定的是,当调用回调方法时,CLR会创建一个I/O线程来执行回调。
我不确定的是,当我调用HttpWebRequest.BeginGetRequestStream()时,CLR是否会创建任何I/O线程?还是只创建一个工作线程来发送请求到设备?

3
一篇好的阅读材料 http://blog.stephencleary.com/2013/11/there-is-no-thread.html - Alberto
3
这种想法没有任何效果。没有线程。BeginXxx() 只是要求 TCP/IP 驱动程序堆栈启动操作。只有当驱动程序响应网络卡上接收到的数据完成请求时,线程才会激活并调用您的回调方法。这样做的明显优点是没有线程闲置浪费一兆字节的内存,仅等待。请搜索“i/o 完成端口”了解更多信息。 - Hans Passant
那么我可以认为,调用HttpWebRequest.BeginGetRequestStream()方法是同步的。这个调用只是将请求发送到设备驱动程序并立即返回。它发生在主线程中。此时没有创建任何线程。直到IO操作完成,才会唤醒一个I/O线程来调用回调函数。我认为所有这些都是正确的吗? - roast_soul
2个回答

3
异步IO无需线程。 不会创建或阻塞线程。这正是使用异步IO的全部意义所在!解除一个线程的阻塞,再阻塞另一个线程有什么用呢?
这方面的内部细节已经被讨论了很多次。基本上,操作系统在IO完成时通知CLR。这导致CLR将您指定的完成回调排队到线程池中。

1

简单来说:你不用担心。

详细解释:

并没有线程。更准确地说,每个异步请求都没有自己的线程。相反,线程池中有一堆I/O线程,它们大多数时候处于“等待”状态,即等待内核在数据可用时唤醒它们。

重要的是,这些线程可以响应任何通知,它们不是(必须)具有选择性的。如果您需要处理1000个响应,则仍然可以使用一个线程来完成 - 只有在这一点上才会请求线程池中的线程;它必须执行回调方法。例如,如果使用同步方法,您将需要保留一千个线程来处理一千个TCP连接。

使用异步方法,您只需要一个IOCP线程,并且只需要生成(或借用)新线程来执行回调 - 这些回调仅在获取新数据/连接/任何内容后执行,并在完成后立即返回到线程池。实际上,这意味着TCP服务器可以使用少量线程处理数千个并发的TCP连接。毕竟,没有必要生成超出CPU处理能力的线程(现在通常是核心数量的两倍左右),而所有不需要CPU的事情(如异步I/O)不需要生成新线程。如果少量的处理线程不够用,则添加更多线程无济于事,不像同步I/O场景下那样有帮助。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接