介绍如何利用DashScope Python和Java SDK中的连接池与对象池机制,在高并发场景下高效调用CosyVoice语音合成服务。
CosyVoice 语音合成服务基于 WebSocket 协议,以支持流式实时通信。然而,在高并发场景下,为每个请求独立创建和销毁 WebSocket 连接会产生巨大的网络与系统资源开销,并引入显著的连接延迟。为优化性能并确保稳定性,DashScope SDK 内置了高效的资源复用机制(如连接池与对象池)。本文档将详细介绍如何利用 DashScope Python 和 Java SDK 中的这些特性,在高并发场景下高效调用 CosyVoice 服务。
Python SDK 通过
Java SDK 通过内置的连接池和自定义的对象池协同工作,实现最佳性能。
环境变量 描述 连接池大小。推荐值:峰值并发数的 2 倍以上。默认值:32。 最大异步请求数。推荐值:与 单主机最大异步请求数。推荐值:与 环境变量 描述 对象池大小。推荐值:峰值并发数的 1.5 至 2 倍。默认值:500。
以下配置基于在指定规格的阿里云服务器上仅运行 CosyVoice 语音合成服务的测试结果。过高的并发数可能导致任务处理延迟。
其中单机并发数指的是同一时刻正在运行的 CosyVoice 语音合成任务数,也可以理解为工作线程数。
在对 DashScope Java SDK 进行并发调用延迟等性能评估时,建议在正式测试前执行充分的预热操作。预热能够确保测量结果准确反映服务在稳定状态下的真实性能,避免因初始连接耗时导致的数据偏差。
DashScope Java SDK 通过全局单例的连接池高效管理和复用 WebSocket 连接,旨在减少频繁建连和断连的开销,提升高并发场景下的处理能力。
该机制的工作特点如下:
在以下场景中,连接池中可能没有可复用的活跃连接,导致请求需要新建连接:
为获取可靠的性能数据,在正式进行性能压测或延迟统计前,请遵循以下预热步骤:
前提条件
- 获取 API Key
- 已安装符合版本要求的 DashScope SDK,建议安装最新版:
- Python SDK:版本 >= 1.25.2
- Java SDK:版本 >= 2.16.6
Python SDK:对象池优化
Python SDK 通过 SpeechSynthesizerObjectPool 实现对象池优化,用于管理和复用 SpeechSynthesizer 对象。
对象池在初始化时会立即创建指定数量的 SpeechSynthesizer 实例并预先建立 WebSocket 连接。从池中获取对象时无需等待连接建立,可直接发起请求,有效降低首包延迟。当任务完成并将对象归还到对象池后,其 WebSocket 连接不会关闭,而是保持活跃状态等待下次任务复用。
实现步骤
1
安装依赖
2
安装 DashScope 依赖:
3
pip install -U dashscope
4
创建并配置对象池
5
对象池大小需要通过
SpeechSynthesizerObjectPool 进行设置。推荐值:峰值并发数的 1.5 至 2 倍。对象池大小不应超过您账户的 QPS(每秒查询率)限制。6
通过以下代码创建全局单例固定大小对象池。对象池在初始化时会立即创建指定数量的
SpeechSynthesizer 对象并建立 WebSocket 连接,因此会有一定耗时。7
from dashscope.audio.tts_v2 import SpeechSynthesizerObjectPool
synthesizer_object_pool = SpeechSynthesizerObjectPool(max_size=20)
8
从对象池中获取 SpeechSynthesizer 对象
9
如果当前未归还的对象数量已超过对象池的最大容量,系统会额外创建一个新的
SpeechSynthesizer 对象。此类新创建的对象需要重新进行初始化并建立 WebSocket 连接,无法利用对象池的既有连接资源,因此不具备复用效果。10
speech_synthesizer = connectionPool.borrow_synthesizer(
model='cosyvoice-v3-flash',
voice='longanyang',
seed=12382,
callback=synthesizer_callback
)
11
进行语音合成
12
调用
SpeechSynthesizer 对象的 call 或 streaming_call 方法进行语音合成。13
归还 SpeechSynthesizer 对象
14
语音合成任务结束后,归还
SpeechSynthesizer 对象,以便后续任务可以复用该对象。不要归还未完成任务或任务失败的对象。15
connectionPool.return_synthesizer(speech_synthesizer)
完整代码
资源管理与异常处理
-
任务成功:当语音合成任务正常完成时,必须调用
connectionPool.return_synthesizer(speech_synthesizer)将SpeechSynthesizer对象归还到池中,以便复用。不要归还未完成任务或任务失败的 SpeechSynthesizer 对象。 -
任务失败:当 SDK 内部或业务逻辑抛出异常导致任务中断时,主动关闭底层的 WebSocket 连接:
speech_synthesizer.close() -
关闭对象池:在所有语音合成任务完成后,通过
connectionPool.shutdown()关闭对象池。 - TaskFailed 报错:在服务出现 TaskFailed 报错时,不需要额外处理。
Java SDK:连接池与对象池优化
Java SDK 通过内置的连接池和自定义的对象池协同工作,实现最佳性能。
- 连接池:SDK 内部集成的 OkHttp3 连接池,负责管理和复用底层的 WebSocket 连接,减少网络握手开销。此功能默认开启。
- 对象池:基于
commons-pool2实现,用于维护一组已预先建立好连接的SpeechSynthesizer对象。从池中获取对象可消除连接建立的延迟,显著降低首包延迟。
实现步骤
1
添加依赖
2
根据项目构建工具,在依赖配置文件中添加 dashscope-sdk-java 和 commons-pool2。
3
以Maven和Gradle为例,配置如下:
4
Maven
Gradle
5
Gradle 项目保存文件后,在命令行切换到项目根目录,执行以下命令更新依赖:
6
./gradlew build --refresh-dependencies
7
Windows 系统使用:
8
gradlew build --refresh-dependencies
9
配置连接池
10
通过环境变量配置连接池关键参数:
11
DASHSCOPE_CONNECTION_POOL_SIZEDASHSCOPE_MAXIMUM_ASYNC_REQUESTSDASHSCOPE_CONNECTION_POOL_SIZE 保持一致。默认值:32。DASHSCOPE_MAXIMUM_ASYNC_REQUESTS_PER_HOSTDASHSCOPE_CONNECTION_POOL_SIZE 保持一致。默认值:32。12
配置对象池
13
通过环境变量配置对象池大小:
14
COSYVOICE_OBJECTPOOL_SIZE15
- 对象池的大小(
COSYVOICE_OBJECTPOOL_SIZE)必须小于或等于连接池的大小(DASHSCOPE_CONNECTION_POOL_SIZE)。否则,当对象池请求对象时,若连接池已满,会导致调用线程阻塞,等待可用连接。 - 对象池大小不应超过您账户的 QPS(每秒查询率)限制。
16
通过如下代码创建对象池:
17
class CosyvoiceObjectPool {
// 这里省略其它代码,完整示例请参见完整代码
public static GenericObjectPool<SpeechSynthesizer> getInstance() {
lock.lock();
if (synthesizerPool == null) {
// 您可以在这里设置对象池的大小。或在环境变量COSYVOICE_OBJECTPOOL_SIZE中设置。
// 建议设置为服务器最大并发连接数的1.5到2倍。
int objectPoolSize = getObjectivePoolSize();
SpeechSynthesizerObjectFactory speechSynthesizerObjectFactory =
new SpeechSynthesizerObjectFactory();
GenericObjectPoolConfig<SpeechSynthesizer> config =
new GenericObjectPoolConfig<>();
config.setMaxTotal(objectPoolSize);
config.setMaxIdle(objectPoolSize);
config.setMinIdle(objectPoolSize);
synthesizerPool =
new GenericObjectPool<>(speechSynthesizerObjectFactory, config);
}
lock.unlock();
return synthesizerPool;
}
}
18
从对象池中获取 SpeechSynthesizer 对象
19
如果当前未归还的对象数量已超过对象池的最大容量,系统会额外创建一个新的
SpeechSynthesizer 对象。此类新创建的对象需要重新进行初始化并建立 WebSocket 连接,无法利用对象池的既有连接资源,因此不具备复用效果。20
synthesizer = CosyvoiceObjectPool.getInstance().borrowObject();
21
进行语音合成
22
调用
SpeechSynthesizer 对象的 call 或 streamingCall 方法进行语音合成。23
归还 SpeechSynthesizer 对象
24
语音合成任务结束后,归还
SpeechSynthesizer 对象,以便后续任务可以复用该对象。不要归还未完成任务或任务失败的对象。25
CosyvoiceObjectPool.getInstance().returnObject(synthesizer);
完整代码
推荐配置
以下配置基于在指定规格的阿里云服务器上仅运行 CosyVoice 语音合成服务的测试结果。过高的并发数可能导致任务处理延迟。
其中单机并发数指的是同一时刻正在运行的 CosyVoice 语音合成任务数,也可以理解为工作线程数。
| 机器配置(阿里云) | 单机最大并发数 | 对象池大小 | 连接池大小 |
|---|---|---|---|
| 4核8GiB | 100 | 500 | 2000 |
| 8核16GiB | 150 | 500 | 2000 |
| 16核32GiB | 200 | 500 | 2000 |
资源管理与异常处理
-
任务成功:当语音合成任务正常完成时,必须调用
GenericObjectPool的returnObject方法将SpeechSynthesizer对象归还到池中,以便复用。在当前代码中,对应CosyvoiceObjectPool.getInstance().returnObject(synthesizer)。不要归还未完成任务或任务失败的 SpeechSynthesizer 对象。 -
任务失败:当 SDK 内部或业务逻辑抛出异常导致任务中断时,必须执行以下两个操作:
- 主动关闭底层的 WebSocket 连接
- 从对象池中废弃该对象,防止被再次使用
- TaskFailed 报错:在服务出现 TaskFailed 报错时,不需要额外处理。
调用预热与耗时统计说明
在对 DashScope Java SDK 进行并发调用延迟等性能评估时,建议在正式测试前执行充分的预热操作。预热能够确保测量结果准确反映服务在稳定状态下的真实性能,避免因初始连接耗时导致的数据偏差。
连接复用机制
DashScope Java SDK 通过全局单例的连接池高效管理和复用 WebSocket 连接,旨在减少频繁建连和断连的开销,提升高并发场景下的处理能力。
该机制的工作特点如下:
- 按需创建:SDK 不会在服务启动时预创建 WebSocket 连接,而是在首次调用时按需建立。
- 限时复用:请求完成后,连接将在池中保留最多 60 秒以备复用。
- 若 60 秒内有新请求,将复用现有连接,避免重复握手开销。
- 若连接空闲超过 60 秒,将被自动关闭以释放资源。
预热的重要性
在以下场景中,连接池中可能没有可复用的活跃连接,导致请求需要新建连接:
- 应用刚启动,尚未发起任何调用。
- 服务空闲时间超过 60 秒,池中连接已因超时而关闭。
推荐做法
为获取可靠的性能数据,在正式进行性能压测或延迟统计前,请遵循以下预热步骤:
- 模拟正式测试的并发级别,提前发起一定数量的调用(例如,持续 1-2 分钟),以充分填充连接池。
- 确认连接池已建立并维持足够的活跃连接后,再开始正式的性能数据采集。
Java SDK 常见异常
异常 1、业务流量平稳,但是服务器 TCP 连接数持续上升
异常 1、业务流量平稳,但是服务器 TCP 连接数持续上升
出错原因:类型一:每一个 SDK 对象创建时都会申请一个连接。如果没有使用对象池,每一次任务结束后对象都被析构。此时这一个连接将进入无引用状态,需要等待 61 秒后服务端报错连接超时才会真正断开,这会导致这个连接在 61 秒内不可复用。在高并发场景下,新的任务在发现没有可复用连接时会创建新连接,会造成如下后果:
- 连接数持续上升。
- 由于连接数过多,服务器资源不足,服务器卡顿。
- 连接池被打满、新任务由于启动时需要等待可用连接而阻塞。
异常 2、任务耗时比正常调用多 60 秒
异常 2、任务耗时比正常调用多 60 秒
同"异常 1",连接池已经达到最大连接限制,新的任务需要等待无引用状态的连接 61 秒触发超时后才可以获得连接。
异常 3、服务启动时任务慢,之后慢慢恢复正常
异常 3、服务启动时任务慢,之后慢慢恢复正常
出错原因:在高并发调用时,同一个对象会复用同一个 WebSocket 连接,因此 WebSocket 连接只会在服务启动时创建。需要注意的是,任务启动阶段如果立刻开始较高并发调用,同时创建过多的 WebSocket 连接会导致阻塞。解决方法:启动服务后逐步提升并发量,或增加预热任务。
异常 4、服务端报错 Invalid action('run-task')! Please follow the protocol!
异常 4、服务端报错 Invalid action('run-task')! Please follow the protocol!
出错原因:这是由于出现了客户端报错后,服务端不知道客户端出错,连接处于任务中状态。此时连接和对象被复用并开启下一个任务,导致流程错误,下一个任务失败。解决方法:在抛出异常后主动关闭 WebSocket 连接后归还对象池。
异常 5、业务流量平稳,调用量出现异常尖刺
异常 5、业务流量平稳,调用量出现异常尖刺
出错原因:同时创建过多 WebSocket 连接导致阻塞,但业务流量持续打进来,导致任务短时间积压,并且在阻塞后所有积压任务立刻调用。这会造成调用量尖刺,并且有可能造成瞬时超过账号的并发数限制导致部分任务失败、服务器卡顿等。这种瞬间创建过多 WebSocket 的情况多发生于:
- 服务启动阶段
- 网络出现异常,大量 WebSocket 连接同时中断重连
- 某一时刻出现大量服务端报错,导致大量 WebSocket 重连。常见报错如并发数超过账号限制("Requests rate limit exceeded, please try again later.")。
- 检查网络情况。
- 排查尖刺前是否出现大量其他服务端报错。
- 提高账号并发限制。
- 调小对象池和连接池大小,通过对象池上限限制最大并发数。
- 提升服务器配置或扩充机器数。
异常 6、随着并发数提升,所有任务都变慢
异常 6、随着并发数提升,所有任务都变慢
解决方法:
- 检查是否已经达到网络带宽上限。
- 检查实际并发数是否已经过高。

