测试拉起1个apiserver,测试并发数目>100,输入长度>500的时候,尝试使用进程池,num=5,其端到端的时延明显小于当前的线程池(num=1)方式.
为什么不使用进程池了?
vLLM官方推荐在高并发测试时使用进程池(如multiprocessing.Pool)而不是单线程或单进程方式,因为进程池能更好地利用多核CPU资源,提升请求并发能力和吞吐量。实际测试中,进程池(num>1)下端到端延迟明显低于单线程/单进程(num=1),这是因为多进程能并行发起和处理请求,减少了请求排队和阻塞时间。相关用法可参考vLLM官方测试脚本。
如果你发现官方脚本默认用进程池,主要是为了模拟真实高并发场景,最大化服务器负载和利用率。单线程/单进程方式会因GIL和I/O等待导致并发能力受限,无法充分压测vLLM的极限性能。如需自定义并发方式,可根据实际需求调整进程池或线程池参数。更多细节见官方文档。需要详细原理分析吗?
Sources:
我的意思是说vllm/entrypoints/serving_engine.py中OpenAIServing的__init__初始化方法中,以下代码片段,为什么使用ThreadPoolExecutor, 不使用ProcessPoolExecutor,
self._tokenizer_executor = ThreadPoolExecutor(max_workers=1)
vLLM在OpenAIServing的__init__
中使用ThreadPoolExecutor(max_workers=1)
,而不是ProcessPoolExecutor
,主要原因是HuggingFace的tokenizer对象通常不是进程安全的,且其初始化和序列化(pickle)开销较大,跨进程传递会导致性能下降和兼容性问题。此外,tokenizer大多为Rust实现,线程池下能释放GIL,获得并发加速,而进程池反而带来不必要的IPC和内存开销。相关讨论见官方PR说明。
综上,线程池(单线程)既保证了线程安全,又避免了进程池的高昂代价和复杂性,是当前vLLM推荐的做法。如需详细原理或对比分析,请告知。
Sources: