【压测数据分享】C#的 `ThreadPool.SetMaxThreads()` 配置最大线程数到底对性能有多大影响
作者:张富春(ahfuzhang),转载时请注明作者和引用链接,谢谢!
结论
先说结论:
- 以 async 的方法 + kestrel 库来提供 http 服务,性能非常强悍。直观感受上,性能不输 golang.
- 物理线程的数量必然影响性能:
- ThreadPool.SetMinThreads( 4,4) ThreadPool.SetMaxThreads(4,4) 线程池的线程数与核数一致时,性能最好。(CPU 占用达到 360%)
- 不限制线程池的最大和最小线程数,性能下降约 1.37%。猜测在任务更复杂的情况下,下降的比例会更明显。(CPU 占用达到 360%)
- ThreadPool.SetMinThreads( 2,2) ThreadPool.SetMaxThreads(2,2) 当线程池最大值只有核数的一半时,性能下降 51.07% (CPU 占用达到 215%)
- 程序中宜限制线程池最大线程数不要超过核数,否则一定产生劣化影响。
- 从稳定性考虑:线程池最大值 = 核数 - 1 是个好主意。
- 某些特定任务可以开额外的线程来运行
- 负责处理请求的线程数稳定,不至于在过载的时候完全卡死整个应用。
- 最重要的:kestrel 的处理路径上完全 async,没有阻塞!
实验方法
- 使用 DotNet 的 Kestrel 库开发一个 http 1.1 的 echo 服务器(请求后,把请求头作为输出)
- 使用了自定义的 metrics 统计方式
- 往 stdout 输出了 json 格式的请求流水日志
- 编译为 linux 下的二进制程序
- 编译参数如下:
dotnet publish $(PROJECT) -c Release -r linux-x64 -p:PublishAot=true --self-contained true -o $(PUBLISH_DIR)
- 在基础镜像
mcr.microsoft.com/dotnet/aspnet:8.0中运行 - docker 运行时绑定到固定的 cpu 上:
- 使用 4 个 cpu 核
docker run \
-d \
--name=kestrel_exp_0 \
--rm \
--cpuset-cpus="8,9,10,11" \
-m 1G \
-p 8081:8081 \
kestrel-server:latest \
/app/KestrelServer -addr=0.0.0.0:8081 -threadpool.min=4 -threadpool.max=4
- 关键实验代码如下:
if (minThreads > 0)
{
ThreadPool.SetMinThreads(minThreads, minThreads);
}
if (maxThreads > 0)
{
ThreadPool.SetMaxThreads(maxThreads, maxThreads);
}
实验数据:
| qps | CPU | |
|---|---|---|
| Threadpool.MaxThread = 核数 | 88594.4 / core / s | 360% |
| Threadpool.MaxThread 不限制 | 87164.7 / core / s | 360% |
| Threadpool.MaxThread = 核数 / 2 | 58645.8 / core / s | 215.70% |
| Threadpool.MaxThread = 核数 * 2 | 81888.8 / core / s | 315% |

浙公网安备 33010602011771号