首页 > 解决方案 > 使用 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 服务器请求数据,将线程返回给线程池,当数据到达时,从池中获取一个线程进行处理结果。

标签: c#.netasynchronousthreadpool

解决方案


我概述了下面的序列,如果我错了,请纠正我

对不起,但你错了。:)

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 的代码的方法。当然,这些会将您的委托排队以在特定的非线程池线程上调用。这更类似于线程池场景,但从技术上讲并非如此,并且在任何情况下仍然只涉及单个线程。


推荐阅读