Skip to content

serve_realtime_ws.py 是单个 asyncio 事件循环管理所有 WebSocket 连接,但解码是同步阻塞 #2966

@qiulang

Description

@qiulang

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仍然是大量空闲

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't workingneeds triageNeeds maintainer triage and routing

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions