通过对象池复用语音合成对象与 WebSocket 连接,配置并发、预热和异常处理,减少重复建连的开销。
适用范围
对象池通过保留合成对象及其 WebSocket 连接,减少反复创建对象、TCP/TLS 握手和协议升级的开销。支持的模型系列和 SDK 如下:
- Qwen-Audio-TTS、CosyVoice:Python、Java 对象池。
- Sambert:Java 对象池,Python SDK 未提供对应的对象池封装。
准备工作
- 获取 API Key并配置
DASHSCOPE_API_KEY,使用与调用地域对应的 API Key。 - 将示例中的
{WorkspaceId}替换为对应地域的业务空间 ID,并按地域设置 WebSocket 地址。
- Python SDK
- Java SDK
Qwen-Audio-TTS、CosyVoice 的对象池需要 DashScope Python SDK 1.25.2 及以上版本:
配置并发与资源池
根据预期同时运行的任务数和服务器规格配置资源池。模型限流按主账号统计,RAM 用户、业务空间和 API Key 共享主账号的额度;各模型的调用频率和并发限制请参见限流。
- 对象池容量可从峰值并发数的 1.5~2 倍开始配置,并根据实际负载调整。
- Python 池内对象全部借出后,仍可能创建额外对象;这些对象在使用时需要新建连接。
- Java 参数
- 服务器配置参考
SDK 环境变量应在 Java 进程启动前设置。下列前 3 项是 SDK 配置,后面的对象池容量变量由示例代码自定义:
本文 Java 示例将
| 环境变量 | 默认值 | 说明 |
|---|---|---|
DASHSCOPE_CONNECTION_POOL_SIZE | 32 | 底层 OkHttp 空闲连接池的配置。 |
DASHSCOPE_MAXIMUM_ASYNC_REQUESTS | 32 | 底层异步请求调度的最大请求数。 |
DASHSCOPE_MAXIMUM_ASYNC_REQUESTS_PER_HOST | 32 | 底层异步请求调度的单主机最大请求数。 |
COSYVOICE_OBJECTPOOL_SIZE | 500 | 本文 Qwen-Audio-TTS/CosyVoice Java 示例的对象池容量,对应 maxTotal 和 maxIdle,不是 SDK 内置参数。 |
SAMBERT_OBJECTPOOL_SIZE | 500 | 本文 Sambert Java 示例的对象池容量,对应 maxTotal 和 maxIdle,不是 SDK 内置参数。 |
maxIdle 和 maxTotal 设为相同值,减少闲置对象被销毁后再次创建的开销。销毁对象时应关闭其连接。达到 maxTotal 后,新的借用请求将等待可用对象。示例代码
Qwen-Audio-TTS/CosyVoice
以下示例使用 qwen-audio-3.1-tts-flash 和 longanhuan_v3.1,并发执行 3 次合成。使用 CosyVoice 时,可将模型和音色分别改为 cosyvoice-v3-flash 和 longanyang;其他模型选择与音色要求参见实时语音合成。
- Python SDK
- Java SDK
Sambert
以下示例共享一个对象池,并发执行 3 次单向流式合成,分别保存为 sambert_0.mp3、sambert_1.mp3 和 sambert_2.mp3。
应用于生产环境
资源管理
- 配置 API Key 和接入地址后,创建共享对象池,供业务任务借用。
- 借用并配置对象:Python 调用
borrow_synthesizer时传入模型、音色、格式和回调;Qwen-Audio-TTS/CosyVoice 的 Java 示例在调用borrowObject后,每次都需通过updateParamAndCallback(param, callback)设置本次任务的参数和回调。 - 执行合成:Qwen-Audio-TTS/CosyVoice 的 Python 对象支持
call或streaming_call,Java 对象支持call或streamingCall。Sambert 使用call(param, callback)执行单向流式合成。 - 任务正常完成后,Python 调用
return_synthesizer,Java 调用returnObject归还对象。未完成或失败的对象不得直接归还:Python 调用对象的close();Java 使用invalidateObject废弃对象,并由工厂关闭连接。 - 所有任务结束后,Python 调用
shutdown(),Java 调用对象池的close(),释放对象池资源。
鉴权与多 API Key
- API Key 仅在 WebSocket 建连握手时通过
Authorization请求头进行鉴权,后续run-task消息不携带 API Key。连接复用期间,修改参数或全局配置中的 API Key 不会改变该连接的鉴权身份,可能导致身份、配额或计费归属与预期不一致。 - Python 应在创建池前设置
dashscope.api_key。池初始化时建立的连接沿用握手时的 API Key,borrow_synthesizer不提供 API Key 参数。SpeechSynthesizerObjectPool是进程内单例,多 API Key 应按进程隔离。 - Java 为不同 API Key 创建独立对象池,同一池始终使用相同的 API Key。Qwen-Audio-TTS/CosyVoice 每次借出对象后都应调用
updateParamAndCallback,但该方法不会为已有连接重新鉴权。
预热与耗时统计
- 服务启动或网络恢复后先执行预热调用,逐步提高并发。性能测试前,可按目标并发持续预热(例如 1~2 分钟),待连接稳定复用后再采集数据。
- Python 对象池初始化时会建立连接;Java
GenericObjectPool按需创建对象,首次合成时才建立连接,因此 Java 连接预热需要实际执行合成请求。 - 首次调用包含 WebSocket 建连开销,应与复用连接后的首包延迟和任务总耗时分别统计。也可通过实时率(RTF,合成总耗时 / 音频时长)评估合成速度。
- 对于 Qwen-Audio-TTS、CosyVoice、Sambert,任务结束后空闲 60 秒会自动断开连接。长时间空闲后的调用应按重新建连的情况评估。
get_first_package_delay() 获取首包延迟,并通过 get_last_request_id() 获取请求 ID,用于关联请求日志。Java 对象通过 getLastRequestId() 获取请求 ID。
常见问题
业务流量平稳,但 TCP 连接数持续上升
频繁创建合成对象而未关闭旧连接,会使连接数持续增长,增加服务器资源开销。检查任务结束后是否正确归还对象,以及不再使用的连接是否关闭。
Java 中,若 maxIdle 小于 maxTotal,对象归还时超出空闲容量的对象会被销毁。如果工厂的 destroyObject 没有关闭 WebSocket,连接可能在对象销毁后仍保持打开。可将 maxIdle 与 maxTotal 设为相同值,减少反复销毁和创建,同时确保销毁对象时关闭连接。
任务出现额外等待或超时
Java 对象池达到 maxTotal 后,借用操作会等待可用对象。检查池容量、对象归还及连接关闭情况,避免任务因等待对象而增加耗时。
服务启动或网络恢复后任务变慢
启动服务或网络恢复后,先执行预热调用并逐步提高并发,避免同时建立大量 WebSocket 连接造成阻塞。
返回 Invalid action('run-task')! Please follow the protocol!
客户端异常中断任务后,服务端可能仍认为上一轮任务正在执行。此时复用连接发送新的 run-task 会造成协议顺序错误。应关闭连接并废弃该对象,再新建连接执行后续任务。
业务流量平稳,但调用量出现尖峰
服务启动、网络中断或大量服务端错误后,集中重连可能使任务积压;连接恢复后,积压任务同时提交又会形成调用尖峰,并可能触发账号限流。
- 检查尖峰前是否出现网络异常或大量服务端错误,例如
Requests rate limit exceeded, please try again later.。 - 控制启动和恢复阶段的并发量。Java 可通过对象池的
maxTotal限制同一池同时借出的对象数。 - 核对账号限流额度;需要提额时,按限流中的流程申请。
- 根据实际负载调整服务器配置或增加机器数。