我在1个月前用的1.3.9, 后来项目结束就没再碰,今天注意到已经升级到 1.4.3 而且注意到 fun_asr_nano 的 ws 服务代码重构了,就测试一下它的性能,对比1.3.9 发现并发性能反而全面下滑 (L20机器), 这是一段 47秒音频测试结果 (测试脚本是之前用的)
for n in 8 10 12 14 16; do
for rep in 1 2 3; do
python funasr-test-scripts/bench_streaming_ws.py \
--server ws://localhost:10095 \
--audio test-audio-sample/古人.wav --concurrency $n
done
done
| Sessions |
1.3.9 |
1.4.3 |
| 8 |
✅ 8/8 · p50 48.4 · 1st 1.3 · RTFx 7.6 |
⚠️ 7-8/8 抖 · p50 72.3 · 1st 0.7 · RTFx 5.1 |
| 10 |
✅ 10/10 · p50 51.6 · RTFx 8.9 |
⚠️ 3-6/10 崩 · p50 ~70-79 · RTFx 5.9 |
| 12 |
✅ 12/12 · p50 54.8 · RTFx 10.0 |
❌ ALL FAILED |
| 14 |
✅ 14/14 · p50 60.7 · RTFx 9.5 |
❌ ping timeout |
| 16 |
✅ 16/16 · p50 64.8 · RTFx 10.7 |
❌ ping timeout |
这个结果让我很意外,所以读了一下 realtime_ws.py 代码,我觉得原因在
async def run_session_work(args, operation, *operation_args, **operation_kwargs):
"""Run blocking session work off-loop without concurrent shared-model access."""
lock = getattr(args, "_session_work_lock", None)
if lock is None:
lock = asyncio.Lock()
args._session_work_lock = lock
async with lock:
return await asyncio.to_thread(operation, *operation_args, **operation_kwargs)
你的注释写得很明白 ”Run blocking session work off-loop without concurrent shared-model access.“ 但问题是 , args 是整个服务进程唯一的一份,所以 args._session_work_lock = 全进程一把锁,所有 WebSocket 连接、所有 session 共享,为了"不并发访问模型",把所有东西都串行了——包括 add_audio(纯 CPU、往 buffer 塞音频,根本不碰模型)。收个音频帧也要等别人 decode 完,这是过度加锁。
而且 vLLM 本身就是为并发批处理设计的(continuous batching)——我觉得本该把多个 session 的 decode 请求同时submit 给 engine,让它 batch 起来一起算(这才是 vLLM 高吞吐的来源)。而这把锁强制一次只提交一个,把 vLLM 最强的能力(batching)锁死了。这解释了 RTFx 封顶 5.1x:engine 一次只收到 1 个请求,永远 batch=1,吞吐 = 单请求速率 × 串行,上不去。
所以我觉得实现很有问题,你再确认一下,别是我哪里看错了。但是测试结果是实在体现的
我在1个月前用的1.3.9, 后来项目结束就没再碰,今天注意到已经升级到 1.4.3 而且注意到 fun_asr_nano 的 ws 服务代码重构了,就测试一下它的性能,对比1.3.9 发现并发性能反而全面下滑 (L20机器), 这是一段 47秒音频测试结果 (测试脚本是之前用的)
这个结果让我很意外,所以读了一下 realtime_ws.py 代码,我觉得原因在
你的注释写得很明白 ”Run blocking session work off-loop without concurrent shared-model access.“ 但问题是 , args 是整个服务进程唯一的一份,所以 args._session_work_lock = 全进程一把锁,所有 WebSocket 连接、所有 session 共享,为了"不并发访问模型",把所有东西都串行了——包括 add_audio(纯 CPU、往 buffer 塞音频,根本不碰模型)。收个音频帧也要等别人 decode 完,这是过度加锁。
而且 vLLM 本身就是为并发批处理设计的(continuous batching)——我觉得本该把多个 session 的 decode 请求同时submit 给 engine,让它 batch 起来一起算(这才是 vLLM 高吞吐的来源)。而这把锁强制一次只提交一个,把 vLLM 最强的能力(batching)锁死了。这解释了 RTFx 封顶 5.1x:engine 一次只收到 1 个请求,永远 batch=1,吞吐 = 单请求速率 × 串行,上不去。
所以我觉得实现很有问题,你再确认一下,别是我哪里看错了。但是测试结果是实在体现的