2

我读了这篇文章,对 IHttpAsyncHandler 有所了解。

根据下图,我调用 AsyncHandler 时创建了 2 个线程。

当一个请求到来时,IIS会抓取一个线程——线程1来处理这个请求,当它调用beginXXX方法时,会创建线程2来处理这个真正的逻辑。

我的问题是:

当线程 2 运行时,连接仍然保持,等待响应。

当线程 2 运行时,线程 1 的状态是什么?是在睡觉吗?还是被释放了?

如果线程 1 正在休眠,当线程 2 完成时,线程 1 被唤醒并发送响应?

如果线程 1 被释放,当线程 2 完成时,是否有一个新线程被创建为线程 1?这个新的线程 1 将响应发送给客户端。

线程 1 和线程 2 在同一个线程池中,不是吗?如果是这样,可用线程数是平衡的,这样做的目的是什么?

在此处输入图像描述

4

1 回答 1

2

您不会将线程池视为一个池。当“线程 1”在 PreRender 完成其工作时,它会返回到池中以用于任何目的。当数据准备好End时,将从线程池中随机选择一个线程并完成其工作并在其上发送响应。该随机线程可能是一个新线程,也可能是之前完成工作并返回到池中的同一个线程。

这一点是在窗口之间BeginEnd该线程被重新调整到池中并且可能正在为其他连接提供服务。这允许您拥有比系统可以处理的并发线程更多的并发连接,在同步版本中,一旦您达到最大并发线程数,您就不能再处理新请求。


让我详细介绍一下正在发生的事情

这是一个显示为基线的两个同步连接请求的时间线,为简单起见,我们将说每个步骤需要 1 毫秒来执行,除了需要19 毫秒PreRender来完成。

╔═══════╦════════════════════════╦════════════════ ══╦═════════════════╦═══════════════════╗
║ 时间 ║ 动作(连接#) ║ 打开连接 ║ 运行线程 ║ 可用线程 ║
╠═══════╬════════════════════════╬════════════════ ══╬═════════════════╬═══════════════════╣
║ 0 毫秒 ║ 连接请求 (1) ║ 0 ║ 0 ║ 2 ║
║ 1 毫秒 ║ 预初始化 (1) ║ 1 ║ 1 ║ 1 ║
║ 2 毫秒 ║ 初始化 (1) ║ 1 ║ 1 ║ 1 ║
║ 3 毫秒 ║ 初始化完成 (1) ║ 1 ║ 1 ║ 1 ║
║ 4 毫秒 ║ 预加载 (1) ║ 1 ║ 1 ║ 1 ║
║ 5 毫秒 ║ 加载完成 (1) ║ 1 ║ 1 ║ 1 ║
║ 6 毫秒 ║ 预渲染 (1) ║ 1 ║ 1 ║ 1 ║
║ 10 毫秒 ║ 连接请求 (2) ║ 1 ║ 1 ║ 1 ║
║ 11 毫秒 ║ 预初始化 (2) ║ 2 ║ 2 ║ 0 ║
║ 12 毫秒 ║ 初始化 (2) ║ 2 ║ 2 ║ 0 ║
║ 13 毫秒 ║ 初始化完成 (2) ║ 2 ║ 2 ║ 0 ║
║ 14 毫秒 ║ 预加载 (2) ║ 2 ║ 2 ║ 0 ║
║ 15 毫秒 ║ 加载完成 (2) ║ 2 ║ 2 ║ 0 ║
║ 16 毫秒 ║ 预渲染 (2) ║ 2 ║ 2 ║ 0 ║
║ 25 毫秒 ║ 预渲染完成 (1) ║ 2 ║ 2 ║ 0 ║
║ 26 毫秒 ║ 保存状态 (1) ║ 2 ║ 2 ║ 0 ║
║ 27 毫秒 ║ SaveStateComplete (1) ║ 2 ║ 2 ║ 0 ║
║ 28 毫秒 ║ 渲染 (1) ║ 2 ║ 2 ║ 0 ║
║ 29 毫秒 ║ 发送响应 (1) ║ 1 ║ 1 ║ 1 ║
║ 35 毫秒 ║ 预渲染完成 (2) ║ 1 ║ 1 ║ 1 ║
║ 36 毫秒 ║ 保存状态 (2) ║ 1 ║ 1 ║ 1 ║
║ 37 毫秒 ║ SaveStateComplete (2) ║ 1 ║ 1 ║ 1 ║
║ 38 毫秒 ║ 渲染 (2) ║ 1 ║ 1 ║ 1 ║
║ 39 毫秒 ║ 发送响应 (2) ║ 0 ║ 0 ║ 2 ║
╚═══════╩════════════════════════╩════════════════ ══╩═════════════════╩═══════════════════╝

这是异步版本的时间表。

╔═══════╦════════════════════════╦════════════════ ══╦═════════════════╦═══════════════════╗
║ 时间 ║ 动作(连接#) ║ 打开连接 ║ 运行线程 ║ 可用线程 ║
╠═══════╬════════════════════════╬════════════════ ══╬═════════════════╬═══════════════════╣
║ 0 毫秒 ║ 连接请求 (1) ║ 0 ║ 0 ║ 2 ║
║ 1 毫秒 ║ 预初始化 (1) ║ 1 ║ 1 ║ 1 ║
║ 2 毫秒 ║ 初始化 (1) ║ 1 ║ 1 ║ 1 ║
║ 3 毫秒 ║ 初始化完成 (1) ║ 1 ║ 1 ║ 1 ║
║ 4 毫秒 ║ 预加载 (1) ║ 1 ║ 1 ║ 1 ║
║ 5 毫秒 ║ 加载完成 (1) ║ 1 ║ 1 ║ 1 ║
║ 6 毫秒 ║ 预渲染 (1) ║ 1 ║ 1 ║ 1 ║
║ 7 毫秒 ║ 开始 (1) ║ 1 ║ 0 ║ 2 ║
║ 10 毫秒 ║ 连接请求 (2) ║ 1 ║ 0 ║ 2 ║
║ 11 毫秒 ║ 预初始化 (2) ║ 2 ║ 1 ║ 1 ║
║ 12 毫秒 ║ 初始化 (2) ║ 2 ║ 1 ║ 1 ║
║ 13 毫秒 ║ 初始化完成 (2) ║ 2 ║ 1 ║ 1 ║
║ 14 毫秒 ║ 预加载 (2) ║ 2 ║ 1 ║ 1 ║
║ 15 毫秒 ║ 加载完成 (2) ║ 2 ║ 1 ║ 1 ║
║ 16 毫秒 ║ 预渲染 (2) ║ 2 ║ 1 ║ 1 ║
║ 17 毫秒 ║ 开始 (2) ║ 2 ║ 0 ║ 2 ║
║ 25 毫秒 ║ 结束 (1) ║ 2 ║ 1 ║ 1 ║
║ 26 毫秒 ║ 预渲染完成 (1) ║ 2 ║ 1 ║ 1 ║
║ 27 毫秒 ║ 保存状态 (1) ║ 2 ║ 1 ║ 1 ║
║ 28 毫秒 ║ SaveStateComplete (1) ║ 2 ║ 1 ║ 1 ║
║ 29 毫秒 ║ 渲染 (1) ║ 2 ║ 1 ║ 1 ║
║ 30 毫秒 ║ 发送响应 (1) ║ 1 ║ 0 ║ 2 ║
║ 35 毫秒 ║ 结束 (2) ║ 1 ║ 1 ║ 1 ║
║ 36 毫秒 ║ 预渲染完成 (2) ║ 1 ║ 1 ║ 1 ║
║ 37 毫秒 ║ 保存状态 (2) ║ 1 ║ 1 ║ 1 ║
║ 38 毫秒 ║ SaveStateComplete (2) ║ 1 ║ 1 ║ 1 ║
║ 39 毫秒 ║ 渲染 (2) ║ 1 ║ 1 ║ 1 ║
║ 40 毫秒 ║ 发送响应 (2) ║ 0 ║ 0 ║ 2 ║
╚═══════╩════════════════════════╩════════════════ ══╩═════════════════╩═══════════════════╝</pre>

现在,当处理两个或更少的连接时,异步并没有真正的好处,事实上,由于额外的开销,它甚至可能会稍微慢一些。

但是,看看当我们有超过 2 个并发连接时会发生什么。

同步:

╔═══════╦════════════════════════╦════════════════ ══╦═════════════════╦═══════════════════╗
║ 时间 ║ 动作(连接#) ║ 打开连接 ║ 运行线程 ║ 可用线程 ║
╠═══════╬════════════════════════╬════════════════ ══╬═════════════════╬═══════════════════╣
║ 0 毫秒 ║ 连接请求 (1) ║ 0 ║ 0 ║ 2 ║
║ 1 毫秒 ║ 预初始化 (1) ║ 1 ║ 1 ║ 1 ║
║ 2 毫秒 ║ 初始化 (1) ║ 1 ║ 1 ║ 1 ║
║ 3 毫秒 ║ 初始化完成 (1) ║ 1 ║ 1 ║ 1 ║
║ 4 毫秒 ║ 预加载 (1) ║ 1 ║ 1 ║ 1 ║
║ 5 毫秒 ║ 加载完成 (1) ║ 1 ║ 1 ║ 1 ║
║ 6 毫秒 ║ 预渲染 (1) ║ 1 ║ 1 ║ 1 ║
║ 10 毫秒 ║ 连接请求 (2) ║ 1 ║ 1 ║ 1 ║
║ 11 毫秒 ║ 预初始化 (2) ║ 2 ║ 2 ║ 0 ║
║ 12 毫秒 ║ 初始化 (2) ║ 2 ║ 2 ║ 0 ║
║ 13 毫秒 ║ 初始化完成 (2) ║ 2 ║ 2 ║ 0 ║
║ 14 毫秒 ║ 预加载 (2) ║ 2 ║ 2 ║ 0 ║
║ 15 毫秒 ║ 加载完成 (2) ║ 2 ║ 2 ║ 0 ║
║ 16 毫秒 ║ 预渲染 (2) ║ 2 ║ 2 ║ 0 ║
║ 20 毫秒 ║ 连接请求 (3) ║ 2 ║ 2 ║ 0 ║
║ 25 毫秒 ║ 预渲染完成 (1) ║ 2 ║ 2 ║ 0 ║
║ 26 毫秒 ║ 保存状态 (1) ║ 2 ║ 2 ║ 0 ║
║ 27 毫秒 ║ SaveStateComplete (1) ║ 2 ║ 2 ║ 0 ║
║ 28 毫秒 ║ 渲染 (1) ║ 2 ║ 2 ║ 0 ║
║ 29 毫秒 ║ 发送响应 (1) ║ 1 ║ 1 ║ 1 ║
║ 30 毫秒 ║ 预初始化 (3) ║ 2 ║ 2 ║ 0 ║
║ 31 毫秒 ║ 初始化 (3) ║ 2 ║ 2 ║ 0 ║
║ 32 毫秒 ║ 初始化完成 (3) ║ 2 ║ 2 ║ 0 ║
║ 33 毫秒 ║ 预加载 (3) ║ 2 ║ 2 ║ 0 ║
║ 34 毫秒 ║ 加载完成 (3) ║ 2 ║ 2 ║ 0 ║
║ 35 毫秒 ║ 预渲染 (3) ║ 2 ║ 2 ║ 0 ║
║ 35 毫秒 ║ 预渲染完成 (2) ║ 2 ║ 2 ║ 0 ║
║ 36 毫秒 ║ 保存状态 (2) ║ 2 ║ 2 ║ 0 ║
║ 37 毫秒 ║ SaveStateComplete (2) ║ 2 ║ 2 ║ 0 ║
║ 38 毫秒 ║ 渲染 (2) ║ 2 ║ 2 ║ 0 ║
║ 39 毫秒 ║ 发送响应 (2) ║ 1 ║ 1 ║ 1 ║
║ 54 毫秒 ║ 预渲染完成 (3) ║ 1 ║ 1 ║ 1 ║
║ 55 毫秒 ║ 保存状态 (3) ║ 1 ║ 1 ║ 1 ║
║ 56 毫秒 ║ SaveStateComplete (3) ║ 1 ║ 1 ║ 1 ║
║ 57 毫秒 ║ 渲染 (3) ║ 1 ║ 1 ║ 1 ║
║ 58 毫秒 ║ 发送响应 (3) ║ 0 ║ 0 ║ 2 ║
╚═══════╩════════════════════════╩════════════════ ══╩═════════════════╩═══════════════════╝

异步:

╔═══════╦════════════════════════╦════════════════ ══╦═════════════════╦═══════════════════╗
║ 时间 ║ 动作(连接#) ║ 打开连接 ║ 运行线程 ║ 可用线程 ║
╠═══════╬════════════════════════╬════════════════ ══╬═════════════════╬═══════════════════╣
║ 0 毫秒 ║ 连接请求 (1) ║ 0 ║ 0 ║ 2 ║
║ 1 毫秒 ║ 预初始化 (1) ║ 1 ║ 1 ║ 1 ║
║ 2 毫秒 ║ 初始化 (1) ║ 1 ║ 1 ║ 1 ║
║ 3 毫秒 ║ 初始化完成 (1) ║ 1 ║ 1 ║ 1 ║
║ 4 毫秒 ║ 预加载 (1) ║ 1 ║ 1 ║ 1 ║
║ 5 毫秒 ║ 加载完成 (1) ║ 1 ║ 1 ║ 1 ║
║ 6 毫秒 ║ 预渲染 (1) ║ 1 ║ 1 ║ 1 ║
║ 7 毫秒 ║ 开始 (1) ║ 1 ║ 0 ║ 2 ║
║ 10 毫秒 ║ 连接请求 (2) ║ 1 ║ 0 ║ 2 ║
║ 11 毫秒 ║ 预初始化 (2) ║ 2 ║ 1 ║ 1 ║
║ 12 毫秒 ║ 初始化 (2) ║ 2 ║ 1 ║ 1 ║
║ 13 毫秒 ║ 初始化完成 (2) ║ 2 ║ 1 ║ 1 ║
║ 14 毫秒 ║ 预加载 (2) ║ 2 ║ 1 ║ 1 ║
║ 15 毫秒 ║ 加载完成 (2) ║ 2 ║ 1 ║ 1 ║
║ 16 毫秒 ║ 预渲染 (2) ║ 2 ║ 1 ║ 1 ║
║ 17 毫秒 ║ 开始 (2) ║ 2 ║ 0 ║ 2 ║
║ 20 毫秒 ║ 连接请求 (3) ║ 3 ║ 0 ║ 2 ║
║ 21 毫秒 ║ 预初始化 (3) ║ 3 ║ 1 ║ 1 ║
║ 22 毫秒 ║ 初始化 (3) ║ 3 ║ 1 ║ 1 ║
║ 23 毫秒 ║ 初始化完成 (3) ║ 3 ║ 1 ║ 1 ║
║ 24 毫秒 ║ 预加载 (3) ║ 3 ║ 1 ║ 1 ║
║ 25 毫秒 ║ 结束 (1) ║ 3 ║ 2 ║ 0 ║
║ 25 毫秒 ║ 加载完成 (3) ║ 3 ║ 2 ║ 0 ║
║ 26 毫秒 ║ 预渲染完成 (1) ║ 3 ║ 2 ║ 0 ║
║ 26 毫秒 ║ 预渲染 (3) ║ 3 ║ 2 ║ 0 ║
║ 27 毫秒 ║ 保存状态 (1) ║ 3 ║ 2 ║ 0 ║
║ 27 毫秒 ║ 开始 (3) ║ 3 ║ 1 ║ 0 ║
║ 28 毫秒 ║ SaveStateComplete (1) ║ 3 ║ 1 ║ 1 ║
║ 29 毫秒 ║ 渲染 (1) ║ 3 ║ 1 ║ 1 ║
║ 30 毫秒 ║ 发送响应 (1) ║ 2 ║ 0 ║ 2 ║
║ 35 毫秒 ║ 结束 (2) ║ 2 ║ 1 ║ 1 ║
║ 36 毫秒 ║ 预渲染完成 (2) ║ 2 ║ 1 ║ 1 ║
║ 37 毫秒 ║ 保存状态 (2) ║ 2 ║ 1 ║ 1 ║
║ 38 毫秒 ║ SaveStateComplete (2) ║ 2 ║ 1 ║ 1 ║
║ 39 毫秒 ║ 渲染 (2) ║ 2 ║ 1 ║ 1 ║
║ 40 毫秒 ║ 发送响应 (2) ║ 1 ║ 0 ║ 2 ║
║ 45 毫秒 ║ 结束 (3) ║ 1 ║ 1 ║ 1 ║
║ 46 毫秒 ║ 预渲染完成 (3) ║ 1 ║ 1 ║ 1 ║
║ 47 毫秒 ║ 保存状态 (3) ║ 1 ║ 1 ║ 1 ║
║ 48 毫秒 ║ SaveStateComplete (3) ║ 1 ║ 1 ║ 1 ║
║ 49 毫秒 ║ 渲染 (3) ║ 1 ║ 1 ║ 1 ║
║ 50 毫秒 ║ 发送响应 (3) ║ 0 ║ 0 ║ 2 ║
╚═══════╩════════════════════════╩════════════════ ══╩═════════════════╩═══════════════════╝

请注意,在同步版本中,连接 3 在 20 毫秒时进入,但它必须等到 30 毫秒,此时线程变得可用于处理请求。相反,异步版本在等待 PreRender 完成时将线程返回到池中,因此连接 3 能够立即开始处理。

所以使用异步不会增加每秒事务数,实际上它可能会稍微降低它。然而,它所做的是增加您的“最大并发事务”计数并增加您的总吞吐量。

于 2014-08-05T14:42:24.350 回答