9.2 异步 在预填充阶段,模型需要接收和处理来自不同用户的多个输入。这时可以利用异步处理技术来提高效率。 先热身一下 流式处理(Streaming) 流式处理采用异步通信方式,减少了不必要的等待和阻塞,提高了系统的并发性能和吞吐量 想象一下,如果用户每次与 ChatGPT 对话时都必须等待整个回答生成完毕再显示结果,这种体验多少不太舒服。因为人类在交流时往往是实时获取信息的,逐字逐句地接收信息更符合自然的交流习惯,对应着在线部署的 TTFT 要求。 vLLM 利用异步生成器 (async generator) 来实现流式输出。
在预填充阶段,模型需要接收和处理来自不同用户的多个输入。这时可以利用异步处理技术来提高效率。
先热身一下~
流式处理采用异步通信方式,减少了不必要的等待和阻塞,提高了系统的并发性能和吞吐量
想象一下,如果用户每次与 ChatGPT 对话时都必须等待整个回答生成完毕再显示结果,这种体验多少不太舒服。因为人类在交流时往往是实时获取信息的,逐字逐句地接收信息更符合自然的交流习惯,对应着在线部署的 TTFT 要求。
vLLM 利用异步生成器 (async generator) 来实现流式输出。这允许模型一边生成 token,一边将其 yield 给调用者,而不需要等待整个响应生成完毕,下面是一个简化的实现:
import asyncio import random async def async_word_generator(sentence): words = sentence.split() for word in words: # 模拟推理时间 await asyncio.sleep(random.uniform(0.3, 1.0)) yield word async def stream_sentence(): sentence = "vLLM 的异步生成器可以实现流式输出 让用户体验更加流畅 同时提高系统效率" async for word in async_word_generator(sentence): print(word, end=' ', flush=True) print() async def main(): await stream_sentence() if __name__ == "__main__": asyncio.run(main())
此外,vLLM 官方给出的 API 服务器示例使用了 FastAPI 框架,它原生支持异步编程。这使得服务器可以高效地处理多个并发的流式请求。
热身结束!真正的并发性能提升主要来自于服务器架构、算法优化和硬件资源,我们以 vLLM 最近的更新内容为例:
在早期的 vLLM 架构中,API 服务器(API Server)和推理引擎(vLLM Engine)运行在同一个 Python 进程中。这意味着所有的 HTTP 请求都由同一进程处理,API Server 接收请求后直接调用 vLLM Engine 进行推理。虽然这种方式在负载较低时能够正常工作,但在高并发场景下,会引发性能瓶颈。
为了解决上述问题,vLLM 在 PR#6883 中引入了新的架构,将 API Server 和 vLLM Engine 分离为两个独立的进程。这两个进程之间通过 ZMQ(ZeroMQ)进行高效的异步通信。

ZMQ 是一种高性能的异步消息库,能够支持异步消息传递,允许 API Server 非阻塞地将请求发给 vLLM Engine。
采用新的架构后,vLLM 在高并发场景下的性能得到了显著提升:

异步处理的引入虽然会带来一定的延迟,但如果用少量延迟换取 GPU 利用率的提升显然是笔划算买卖。随着批量处理请求增加,系统的并发处理能力也随之增强。

在引入异步输出处理之前,GPU 在每次完成前向计算后,必须等待 CPU 完成输出处理才能继续执行下一步。这导致了大量的 GPU 空闲时间,限制了 GPU 计算资源的充分利用。
通过引入异步输出处理,输出处理与模型前向计算并行进行。在执行第 n 步计算时,vLLM 并不会等待第 n 步的输出处理完成,而是立即开始第 n+1 步的模型推理。此时,CPU 会并行处理第 n 步的输出。
由于 GPU 不再需要等待 CPU 处理输出数据,GPU 的计算资源得到了充分利用。这样可以减少 GPU 的空闲时间,提升吞吐量和整体性能,vLLM 的每个输出 token 的处理时间(Time-Per-Output-Token, TPOT)得到了显著优化。例如,在 Llama 70B 模型和 4xH100 GPU 的场景下,TPOT 提升了 8.7%,即 GPU 处理速度提高,使得推理能力大幅度增强。