我阅读了this article并了解了有关IHttpAsyncHandler的信息。
根据下图,我调用AsyncHandler时会创建2个线程。
当一个请求到来时,IIS将获取一个线程 - 线程1来处理这个请求,当它调用beginXXX方法时,线程2将被创建并处理这个真实的逻辑。
我的问题是:
当线程2运行时,连接仍然存在,等待响应。
当线程2运行时,线程1的状态是什么?它在睡觉吗?或者它被释放?
如果线程1正在休眠,当线程2完成时,线程1被唤醒并发送响应??
如果线程1被释放,当线程2完成时,是否有一个新线程被创建为线程1?这个新的线程1将响应发送给客户端。
线程1和线程2在同一个线程池中,不是吗? 如果是这样,可用的线程数是平衡的,这样做的目的是什么?
答案 0 :(得分:2)
您没有将线程池视为池。当"线程1"完成其在PreRender的工作后,它将返回池中以便出于任何目的重复使用。数据准备好后End
将从线程池中选择一个随机线程并完成其工作并在其上发送响应。该随机线程可以是一个新线程,也可以是与之前返回池中的工作相同的线程。
这一点在Begin
和End
之间的窗口中,该线程被重新调整到池中,并且可以为其他连接提供服务。这使您可以拥有比系统可以处理的并发线程更多的并发连接,在同步版本中,一旦达到最大并发线程数,就无法再处理新请求。
让我进一步了解正在发生的事情
这是两个同步连接请求显示为基线的时间线,为简单起见,我们将说每个步骤需要1ms才能执行,PreRender
除外,需要19ms才能完成。
╔═══════╦════════════════════════╦══════════════════╦═════════════════╦═══════════════════╗ ║ Time ║ Action (Connection #) ║ Open Connections ║ Running Threads ║ Available Threads ║ ╠═══════╬════════════════════════╬══════════════════╬═════════════════╬═══════════════════╣ ║ 0 ms ║ Connection Request (1) ║ 0 ║ 0 ║ 2 ║ ║ 1 ms ║ PreInit (1) ║ 1 ║ 1 ║ 1 ║ ║ 2 ms ║ Init (1) ║ 1 ║ 1 ║ 1 ║ ║ 3 ms ║ InitComplete (1) ║ 1 ║ 1 ║ 1 ║ ║ 4 ms ║ PreLoad (1) ║ 1 ║ 1 ║ 1 ║ ║ 5 ms ║ LoadComplete (1) ║ 1 ║ 1 ║ 1 ║ ║ 6 ms ║ PreRender (1) ║ 1 ║ 1 ║ 1 ║ ║ 10 ms ║ Connection Request (2) ║ 1 ║ 1 ║ 1 ║ ║ 11 ms ║ PreInit (2) ║ 2 ║ 2 ║ 0 ║ ║ 12 ms ║ Init (2) ║ 2 ║ 2 ║ 0 ║ ║ 13 ms ║ InitComplete (2) ║ 2 ║ 2 ║ 0 ║ ║ 14 ms ║ PreLoad (2) ║ 2 ║ 2 ║ 0 ║ ║ 15 ms ║ LoadComplete (2) ║ 2 ║ 2 ║ 0 ║ ║ 16 ms ║ PreRender (2) ║ 2 ║ 2 ║ 0 ║ ║ 25 ms ║ PreRenderComplete (1) ║ 2 ║ 2 ║ 0 ║ ║ 26 ms ║ SaveState (1) ║ 2 ║ 2 ║ 0 ║ ║ 27 ms ║ SaveStateComplete (1) ║ 2 ║ 2 ║ 0 ║ ║ 28 ms ║ Render (1) ║ 2 ║ 2 ║ 0 ║ ║ 29 ms ║ Send Response (1) ║ 1 ║ 1 ║ 1 ║ ║ 35 ms ║ PreRenderComplete (2) ║ 1 ║ 1 ║ 1 ║ ║ 36 ms ║ SaveState (2) ║ 1 ║ 1 ║ 1 ║ ║ 37 ms ║ SaveStateComplete (2) ║ 1 ║ 1 ║ 1 ║ ║ 38 ms ║ Render (2) ║ 1 ║ 1 ║ 1 ║ ║ 39 ms ║ Send Response (2) ║ 0 ║ 0 ║ 2 ║ ╚═══════╩════════════════════════╩══════════════════╩═════════════════╩═══════════════════╝
以下是异步版本的时间表。
╔═══════╦════════════════════════╦══════════════════╦═════════════════╦═══════════════════╗ ║ Time ║ Action (Connection #) ║ Open Connections ║ Running Threads ║ Available Threads ║ ╠═══════╬════════════════════════╬══════════════════╬═════════════════╬═══════════════════╣ ║ 0 ms ║ Connection Request (1) ║ 0 ║ 0 ║ 2 ║ ║ 1 ms ║ PreInit (1) ║ 1 ║ 1 ║ 1 ║ ║ 2 ms ║ Init (1) ║ 1 ║ 1 ║ 1 ║ ║ 3 ms ║ InitComplete (1) ║ 1 ║ 1 ║ 1 ║ ║ 4 ms ║ PreLoad (1) ║ 1 ║ 1 ║ 1 ║ ║ 5 ms ║ LoadComplete (1) ║ 1 ║ 1 ║ 1 ║ ║ 6 ms ║ PreRender (1) ║ 1 ║ 1 ║ 1 ║ ║ 7 ms ║ Begin (1) ║ 1 ║ 0 ║ 2 ║ ║ 10 ms ║ Connection Request (2) ║ 1 ║ 0 ║ 2 ║ ║ 11 ms ║ PreInit (2) ║ 2 ║ 1 ║ 1 ║ ║ 12 ms ║ Init (2) ║ 2 ║ 1 ║ 1 ║ ║ 13 ms ║ InitComplete (2) ║ 2 ║ 1 ║ 1 ║ ║ 14 ms ║ PreLoad (2) ║ 2 ║ 1 ║ 1 ║ ║ 15 ms ║ LoadComplete (2) ║ 2 ║ 1 ║ 1 ║ ║ 16 ms ║ PreRender (2) ║ 2 ║ 1 ║ 1 ║ ║ 17 ms ║ Begin (2) ║ 2 ║ 0 ║ 2 ║ ║ 25 ms ║ End (1) ║ 2 ║ 1 ║ 1 ║ ║ 26 ms ║ PreRenderComplete (1) ║ 2 ║ 1 ║ 1 ║ ║ 27 ms ║ SaveState (1) ║ 2 ║ 1 ║ 1 ║ ║ 28 ms ║ SaveStateComplete (1) ║ 2 ║ 1 ║ 1 ║ ║ 29 ms ║ Render (1) ║ 2 ║ 1 ║ 1 ║ ║ 30 ms ║ Send Response (1) ║ 1 ║ 0 ║ 2 ║ ║ 35 ms ║ End (2) ║ 1 ║ 1 ║ 1 ║ ║ 36 ms ║ PreRenderComplete (2) ║ 1 ║ 1 ║ 1 ║ ║ 37 ms ║ SaveState (2) ║ 1 ║ 1 ║ 1 ║ ║ 38 ms ║ SaveStateComplete (2) ║ 1 ║ 1 ║ 1 ║ ║ 39 ms ║ Render (2) ║ 1 ║ 1 ║ 1 ║ ║ 40 ms ║ Send Response (2) ║ 0 ║ 0 ║ 2 ║ ╚═══════╩════════════════════════╩══════════════════╩═════════════════╩═══════════════════╝
现在处理两个或更少的连接时,异步没有真正的好处,实际上由于额外的开销,它甚至可能会稍微慢一些。
但是看看当我们有超过2个并发连接时会发生什么。
同步:
╔═══════╦════════════════════════╦══════════════════╦═════════════════╦═══════════════════╗ ║ Time ║ Action (Connection #) ║ Open Connections ║ Running Threads ║ Available Threads ║ ╠═══════╬════════════════════════╬══════════════════╬═════════════════╬═══════════════════╣ ║ 0 ms ║ Connection Request (1) ║ 0 ║ 0 ║ 2 ║ ║ 1 ms ║ PreInit (1) ║ 1 ║ 1 ║ 1 ║ ║ 2 ms ║ Init (1) ║ 1 ║ 1 ║ 1 ║ ║ 3 ms ║ InitComplete (1) ║ 1 ║ 1 ║ 1 ║ ║ 4 ms ║ PreLoad (1) ║ 1 ║ 1 ║ 1 ║ ║ 5 ms ║ LoadComplete (1) ║ 1 ║ 1 ║ 1 ║ ║ 6 ms ║ PreRender (1) ║ 1 ║ 1 ║ 1 ║ ║ 10 ms ║ Connection Request (2) ║ 1 ║ 1 ║ 1 ║ ║ 11 ms ║ PreInit (2) ║ 2 ║ 2 ║ 0 ║ ║ 12 ms ║ Init (2) ║ 2 ║ 2 ║ 0 ║ ║ 13 ms ║ InitComplete (2) ║ 2 ║ 2 ║ 0 ║ ║ 14 ms ║ PreLoad (2) ║ 2 ║ 2 ║ 0 ║ ║ 15 ms ║ LoadComplete (2) ║ 2 ║ 2 ║ 0 ║ ║ 16 ms ║ PreRender (2) ║ 2 ║ 2 ║ 0 ║ ║ 20 ms ║ Connection Request (3) ║ 2 ║ 2 ║ 0 ║ ║ 25 ms ║ PreRenderComplete (1) ║ 2 ║ 2 ║ 0 ║ ║ 26 ms ║ SaveState (1) ║ 2 ║ 2 ║ 0 ║ ║ 27 ms ║ SaveStateComplete (1) ║ 2 ║ 2 ║ 0 ║ ║ 28 ms ║ Render (1) ║ 2 ║ 2 ║ 0 ║ ║ 29 ms ║ Send Response (1) ║ 1 ║ 1 ║ 1 ║ ║ 30 ms ║ PreInit (3) ║ 2 ║ 2 ║ 0 ║ ║ 31 ms ║ Init (3) ║ 2 ║ 2 ║ 0 ║ ║ 32 ms ║ InitComplete (3) ║ 2 ║ 2 ║ 0 ║ ║ 33 ms ║ PreLoad (3) ║ 2 ║ 2 ║ 0 ║ ║ 34 ms ║ LoadComplete (3) ║ 2 ║ 2 ║ 0 ║ ║ 35 ms ║ PreRender (3) ║ 2 ║ 2 ║ 0 ║ ║ 35 ms ║ PreRenderComplete (2) ║ 2 ║ 2 ║ 0 ║ ║ 36 ms ║ SaveState (2) ║ 2 ║ 2 ║ 0 ║ ║ 37 ms ║ SaveStateComplete (2) ║ 2 ║ 2 ║ 0 ║ ║ 38 ms ║ Render (2) ║ 2 ║ 2 ║ 0 ║ ║ 39 ms ║ Send Response (2) ║ 1 ║ 1 ║ 1 ║ ║ 54 ms ║ PreRenderComplete (3) ║ 1 ║ 1 ║ 1 ║ ║ 55 ms ║ SaveState (3) ║ 1 ║ 1 ║ 1 ║ ║ 56 ms ║ SaveStateComplete (3) ║ 1 ║ 1 ║ 1 ║ ║ 57 ms ║ Render (3) ║ 1 ║ 1 ║ 1 ║ ║ 58 ms ║ Send Response (3) ║ 0 ║ 0 ║ 2 ║ ╚═══════╩════════════════════════╩══════════════════╩═════════════════╩═══════════════════╝
异步:
╔═══════╦════════════════════════╦══════════════════╦═════════════════╦═══════════════════╗ ║ Time ║ Action (Connection #) ║ Open Connections ║ Running Threads ║ Available Threads ║ ╠═══════╬════════════════════════╬══════════════════╬═════════════════╬═══════════════════╣ ║ 0 ms ║ Connection Request (1) ║ 0 ║ 0 ║ 2 ║ ║ 1 ms ║ PreInit (1) ║ 1 ║ 1 ║ 1 ║ ║ 2 ms ║ Init (1) ║ 1 ║ 1 ║ 1 ║ ║ 3 ms ║ InitComplete (1) ║ 1 ║ 1 ║ 1 ║ ║ 4 ms ║ PreLoad (1) ║ 1 ║ 1 ║ 1 ║ ║ 5 ms ║ LoadComplete (1) ║ 1 ║ 1 ║ 1 ║ ║ 6 ms ║ PreRender (1) ║ 1 ║ 1 ║ 1 ║ ║ 7 ms ║ Begin (1) ║ 1 ║ 0 ║ 2 ║ ║ 10 ms ║ Connection Request (2) ║ 1 ║ 0 ║ 2 ║ ║ 11 ms ║ PreInit (2) ║ 2 ║ 1 ║ 1 ║ ║ 12 ms ║ Init (2) ║ 2 ║ 1 ║ 1 ║ ║ 13 ms ║ InitComplete (2) ║ 2 ║ 1 ║ 1 ║ ║ 14 ms ║ PreLoad (2) ║ 2 ║ 1 ║ 1 ║ ║ 15 ms ║ LoadComplete (2) ║ 2 ║ 1 ║ 1 ║ ║ 16 ms ║ PreRender (2) ║ 2 ║ 1 ║ 1 ║ ║ 17 ms ║ Begin (2) ║ 2 ║ 0 ║ 2 ║ ║ 20 ms ║ Connection Request (3) ║ 3 ║ 0 ║ 2 ║ ║ 21 ms ║ PreInit (3) ║ 3 ║ 1 ║ 1 ║ ║ 22 ms ║ Init (3) ║ 3 ║ 1 ║ 1 ║ ║ 23 ms ║ InitComplete (3) ║ 3 ║ 1 ║ 1 ║ ║ 24 ms ║ PreLoad (3) ║ 3 ║ 1 ║ 1 ║ ║ 25 ms ║ End (1) ║ 3 ║ 2 ║ 0 ║ ║ 25 ms ║ LoadComplete (3) ║ 3 ║ 2 ║ 0 ║ ║ 26 ms ║ PreRenderComplete (1) ║ 3 ║ 2 ║ 0 ║ ║ 26 ms ║ PreRender (3) ║ 3 ║ 2 ║ 0 ║ ║ 27 ms ║ SaveState (1) ║ 3 ║ 2 ║ 0 ║ ║ 27 ms ║ Begin (3) ║ 3 ║ 1 ║ 0 ║ ║ 28 ms ║ SaveStateComplete (1) ║ 3 ║ 1 ║ 1 ║ ║ 29 ms ║ Render (1) ║ 3 ║ 1 ║ 1 ║ ║ 30 ms ║ Send Response (1) ║ 2 ║ 0 ║ 2 ║ ║ 35 ms ║ End (2) ║ 2 ║ 1 ║ 1 ║ ║ 36 ms ║ PreRenderComplete (2) ║ 2 ║ 1 ║ 1 ║ ║ 37 ms ║ SaveState (2) ║ 2 ║ 1 ║ 1 ║ ║ 38 ms ║ SaveStateComplete (2) ║ 2 ║ 1 ║ 1 ║ ║ 39 ms ║ Render (2) ║ 2 ║ 1 ║ 1 ║ ║ 40 ms ║ Send Response (2) ║ 1 ║ 0 ║ 2 ║ ║ 45 ms ║ End (3) ║ 1 ║ 1 ║ 1 ║ ║ 46 ms ║ PreRenderComplete (3) ║ 1 ║ 1 ║ 1 ║ ║ 47 ms ║ SaveState (3) ║ 1 ║ 1 ║ 1 ║ ║ 48 ms ║ SaveStateComplete (3) ║ 1 ║ 1 ║ 1 ║ ║ 49 ms ║ Render (3) ║ 1 ║ 1 ║ 1 ║ ║ 50 ms ║ Send Response (3) ║ 0 ║ 0 ║ 2 ║ ╚═══════╩════════════════════════╩══════════════════╩═════════════════╩═══════════════════╝
请注意,在同步版本中,连接3在20ms时进入,但是当线程可用于处理请求时,它必须等到30ms。相比之下,异步版本在等待PreRender完成时将线程返回到池中,因此连接3立即能够开始处理。
因此,使用async不会增加每秒事务数,实际上它可能会略微降低每秒事务数。然而,它所做的是增加你的" Max Concurrent Transaction"计算并增加总吞吐量。