您不会将线程池视为一个池。当“线程 1”在 PreRender 完成其工作时,它会返回到池中以用于任何目的。当数据准备好End
时,将从线程池中随机选择一个线程并完成其工作并在其上发送响应。该随机线程可能是一个新线程,也可能是之前完成工作并返回到池中的同一个线程。
这一点是在窗口之间Begin
,End
该线程被重新调整到池中并且可能正在为其他连接提供服务。这允许您拥有比系统可以处理的并发线程更多的并发连接,在同步版本中,一旦您达到最大并发线程数,您就不能再处理新请求。
让我详细介绍一下正在发生的事情
这是一个显示为基线的两个同步连接请求的时间线,为简单起见,我们将说每个步骤需要 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 能够立即开始处理。
所以使用异步不会增加每秒事务数,实际上它可能会稍微降低它。然而,它所做的是增加您的“最大并发事务”计数并增加您的总吞吐量。