c# - 使用 APM BeginXX、EndXXX 方法时是否涉及两个线程?
问题描述
例如,我们有以下 APM API:
public virtual IAsyncResult BeginGetResponse(AsyncCallback callback, object state);
public virtual WebResponse EndGetResponse(IAsyncResult asyncResult);
所以当我BeginGetResponse
在主线程中调用时,我概述了下面的序列,如果我错了,请纠正我
1-主线程在线程池上排队请求工作。
2-一段时间后,线程池分配一个线程来发送请求。然后这个线程被回收回线程池。
3-一旦所有数据到达,线程池分配一个新的线程来处理结果,我们可以EndGetResponse
在这个线程中调用来获取结果。
所以除了主线程之外,还有两个新线程来完成工作,我的理解是否正确?如果是,这些新线程都是 I/O 线程,还是第一个是 IO 线程而第二个线程是工作线程?
编辑:
以下是我教科书中的引文:
一个更有效的方法(即使用 BeginXXX 和 EndXXX)是创建一个线程从 web 服务器请求数据,将线程返回给线程池,当数据到达时,从池中获取一个线程进行处理结果。
解决方案
我概述了下面的序列,如果我错了,请纠正我
对不起,但你错了。:)
1-主线程在线程池上排队请求工作
不。作为一般规则,表单的方法唯一一次将BeginXXX()
某些东西排队到线程池是BeginInvoke()
委托类型上的方法。
否则,通常的实现(在 Windows 上)是使用“I/O 完成端口”(IOCP)。这最终将导致您的回调方法在 IOCP 线程池中的线程上执行,但在第 1 步,唯一发生的事情是 I/O 操作已启动,并将其与 I/O 完成端口相关联。
2-一段时间后,线程池分配一个线程来发送请求。然后这个线程被回收回线程池。
这一步永远不会发生。
3-一旦所有数据到达,线程池分配一个新的线程来处理结果,我们可以在这个线程中调用EndGetResponse来获取结果。
此步骤是线程池线程执行代码的唯一步骤。并且要明确:线程在 IOCP 线程池中,而不是常规线程池中。
发生的情况是,当初始 I/O 操作启动时,底层本机 Windows 调用将 I/O 完成端口与其关联。该端口是本机 Windows API 中的一项功能,它允许 Windows 在 I/O 操作完成时自动唤醒线程池中的线程。这会执行一些 .NET 代码,然后依次执行您的代码以最终解决操作。
当然,也有例外。对于实现该BeginXXX()/EndXXX()
模式的类,没有强制执行上述内容。但这始终是 .NET 组件实现它的方式。而且由于对于实现它的第三方组件,它们通常不会直接调用本机 API,而是会使用一些 .NET IO 对象(通常是FileStream
,Socket
或其他一些最终依赖于这两个类之一的类),即使他们最终也会使用 IOCP 作为底层实现。
请注意,还有另一个突出的例外,即既不使用线程池也不使用 IOCP:BeginInvoke()
Winforms 或基于 WPF/Dispatcher 的代码的方法。当然,这些会将您的委托排队以在特定的非线程池线程上调用。这更类似于线程池场景,但从技术上讲并非如此,并且在任何情况下仍然只涉及单个线程。
推荐阅读
- python-3.x - GeoPandas dataFrame using iterrows() to fill a dictionary with column data
- swift - Reflection in Swift
- mysql - how to display two queries in one mysql table
- php - json_decode getting JSON_ERROR_SYNTAX on POST request
- spring-kafka - @EventListener 中的 SPEL 表达式
- python - tf.keras 卷积架构不起作用
- html - Bootstrap 输入背景不覆盖整个输入
- r - lm 的系数太多
- tensorflow - 为 LSTM RNN 预测时间序列动态找到正确的时间步长
- ruby-on-rails - 在 Rails API 响应中获取未找到记录的部分原始 SQL