FunASR Version
1.3.5+
Python Version
3.12
Bug Description
单卡流式并发的上限,主要来自 serve_realtime_ws.py 里单个 asyncio 事件循环的串行化,同步的 decode() 阻塞整个 loop,而不是 GPU 算力 / KV cache / LLM decoder。
RealtimeASRSession.decode()(partial 与 segment 都经它)内部直接调 vllm_engine.generate(...),同步返回——执行期间整个事件循环冻结,其余连接收不到音频、发不出结果。
add_audio() 在 VAD 检测到句尾时立即同步调用 _decode_segment(),不等定时器——所以接收音频的过程中也会被突然阻塞。
结果:N 路并发时,任一路触发 decode,其余 N-1 路全部停住直到本次 decode 完成。所以加 GPU 算力没用。
我尝试了三种办法修改代码都失败:
A. asyncio 改异步 / 线程(AsyncLLMEngine):把同步 decode() 改成 await、把 encoder 前向丢进线程池、LLM 换 AsyncLLMEngine,想让事件循环在 decode 期间不被独占。
结果:原来只能跑32路现在64 路能全部完成,但首词响应飙到 8.34s。原因是 encoder 在线程池里仍被 CUDA 强制串行(同一 context 的 kernel 发射本就排队),异步引擎又会攒批,延迟反而累积——没有真正绕开串行,只是把串行挪了位置。
B. 跨 session 批量 decode:把多路的 encoder 前向合批送 vLLM。32 路内 RTFx 13x→29x(说明 encoder 内部本就支持真批量),但 48 路以上队列积压、首词 5.81s。
C. 禁用 CTC 时间戳:A/B 逐行一致,无效
想请教两个问题:
我这个判断是不是正确。如果想提升并发量是不是只能起多个进程了?
(AsyncLLMEngine/线程池)这条路是我的实现方式不对,还是这条路本身在当前 encoder+vLLM 结构下确实绕不开 CUDA 串行?
Steps to Reproduce
租用单卡,双卡GPU,对照GPU使用情况,可以发现即便在压力测试下,GPU仍然是大量空闲
FunASR Version
1.3.5+
Python Version
3.12
Bug Description
单卡流式并发的上限,主要来自 serve_realtime_ws.py 里单个 asyncio 事件循环的串行化,同步的 decode() 阻塞整个 loop,而不是 GPU 算力 / KV cache / LLM decoder。
RealtimeASRSession.decode()(partial 与 segment 都经它)内部直接调 vllm_engine.generate(...),同步返回——执行期间整个事件循环冻结,其余连接收不到音频、发不出结果。
add_audio() 在 VAD 检测到句尾时立即同步调用 _decode_segment(),不等定时器——所以接收音频的过程中也会被突然阻塞。
结果:N 路并发时,任一路触发 decode,其余 N-1 路全部停住直到本次 decode 完成。所以加 GPU 算力没用。
我尝试了三种办法修改代码都失败:
A. asyncio 改异步 / 线程(AsyncLLMEngine):把同步 decode() 改成 await、把 encoder 前向丢进线程池、LLM 换 AsyncLLMEngine,想让事件循环在 decode 期间不被独占。
结果:原来只能跑32路现在64 路能全部完成,但首词响应飙到 8.34s。原因是 encoder 在线程池里仍被 CUDA 强制串行(同一 context 的 kernel 发射本就排队),异步引擎又会攒批,延迟反而累积——没有真正绕开串行,只是把串行挪了位置。
B. 跨 session 批量 decode:把多路的 encoder 前向合批送 vLLM。32 路内 RTFx 13x→29x(说明 encoder 内部本就支持真批量),但 48 路以上队列积压、首词 5.81s。
C. 禁用 CTC 时间戳:A/B 逐行一致,无效
想请教两个问题:
我这个判断是不是正确。如果想提升并发量是不是只能起多个进程了?
(AsyncLLMEngine/线程池)这条路是我的实现方式不对,还是这条路本身在当前 encoder+vLLM 结构下确实绕不开 CUDA 串行?
Steps to Reproduce
租用单卡,双卡GPU,对照GPU使用情况,可以发现即便在压力测试下,GPU仍然是大量空闲