首页 > 其他分享 >使用ThreadPool.SetMinThreads方法提升API服务响应性能

使用ThreadPool.SetMinThreads方法提升API服务响应性能

时间:2024-04-22 09:44:58浏览次数:14  
标签:finished00 00 Task started00 ThreadPool API 线程 SetMinThreads 空闲

 

使用该方法的背景?

某个API服务在每日请求量40W的情况下,流量增多时会产生大量请求异常:The operation was canceled,从实际情况来看,并不是外部依赖接口或者服务实例不足导致,于是设置线程池数量后,服务性能提升效果显著。

方法定义: 设置线程池在新请求预测中维护的空闲线程数。

public static bool SetMinThreads (int workerThreads, int completionPortThreads)
参数:

workerThreads:要由线程池维护的新的最小空闲辅助线程数。
completionPortThreads:要由线程池维护的新的最小空闲异步 I/O 线程数。
返回值:

如果更改成功,则为 true;否则为 false。

默认的线程池设置是什么?

使用ThreadPool.GetMinThreads方法获取默认的线程池中工作线程及异步I/O线程数量,该数量默认为CPU的物理核心数,在我电脑测试则两个值都为6。

ThreadPool.GetMinThreads(out int workerThreads, out int completionPortThreads);
线程池中可设置的线程数量最大值是多少?

工作线程最大值为:32767,异步I/O线程最大值为:1000,该数量与CPU核心数无关,如果使用SetMinThreads方法时,数量大于可设置的最大值时,将设置失败,即SetMinThreads方法返回false,表示更改失败。

//以下两次调用ThreadPool.SetMinThreads将返回false
ThreadPool.GetMaxThreads(out int workerThreads, out int completionPortThreads);
var result_workerThreads = ThreadPool.SetMinThreads(100, completionPortThreads + 1);
var result_completionPortThreads = ThreadPool.SetMinThreads(workerThreads + 1, completionPortThreads);
什么情况下应该去设置线程池中的线程数量?

您可能需要调整空闲线程数,以实现最佳的总体性能。对于那些在一段时间不活动之后爆发大量活动的应用,少量增加空闲线程数可以显著提高吞吐量。

以上是微软官方文档的建议,意思很明确了,就是服务的流量在不平稳的情况下,而且不定时会有流量高峰,那么调整空闲线程数会是建议的选择。

线程数量应该设置多少比较合适?

首先,不要把线程数设置为比默认值(即CPU核心数)更低的值,当然一般不会这么做,这就是反向优化了,因为这会对性能造成很大影响。
【默认值 - 最大值】这个范围都是允许的线程数量取值范围,具体的设置值应该参考物理机的性能及服务的负载情况,常见的取值范围为100-300,维护大量的空闲线程会消耗系统资源,应以能够解决服务性能问题的最小线程数为设置参考值,如经过测试将线程数设置为100可解决服务的大量超时问题,则建议将线程数量设置为150即可。
线程池数量不足时对性能影响的简单测试:

代码如下:设置线程池最小空闲线程为6,最大值为10,向线程池中添加20个任务,观察执行时间

public async static Task Main()
{
ThreadPool.SetMinThreads(6, 6);
ThreadPool.SetMaxThreads(10, 10);

Stopwatch watch = new Stopwatch();
watch.Start();

void callback(object index)
{
    Console.WriteLine(String.Format("{0}: Task {1} started", watch.Elapsed, index));
    Thread.Sleep(10000);
    Console.WriteLine(String.Format("{0}: Task {1} finished", watch.Elapsed, index));
}

for (int i = 0; i < 20; i++)
{
    ThreadPool.QueueUserWorkItem(callback, i);
}

Console.ReadKey();

}
输出结果如下:

00:00:00.0510352: Task 1 started
00:00:00.0510410: Task 3 started
00:00:00.0510345: Task 2 started
00:00:00.0510340: Task 0 started
00:00:00.0510520: Task 4 started
00:00:00.0510603: Task 5 started

这里开始已经超过了最小的空闲线程数,需要开始创建新线程

结论:在最小空闲线程数范围内,任务会立即开始执行

00:00:00.8377380: Task 6 started
00:00:01.8375997: Task 7 started
00:00:02.8375141: Task 8 started
00:00:03.8355775: Task 9 started

在空闲线程内的任务数量是立即开始的,而以上四个新线程创建时却花了将近4秒才创建并开始任务,
开销惊人

结论:线程数量不足时去创建线程非常耗时,如果突然有大量请求进入,耗时可想而知

00:00:10.1052187: Task 5 finished
00:00:10.1052447: Task 2 finished
00:00:10.1052449: Task 0 finished
00:00:10.1052572: Task 1 finished
00:00:10.1052602: Task 3 finished
00:00:10.1052599: Task 4 finished

00:00:10.1053114: Task 10 started
00:00:10.1064071: Task 11 started
00:00:10.1064901: Task 12 started
00:00:10.1065869: Task 13 started
00:00:10.1066193: Task 14 started
00:00:10.1066530: Task 15 started

在线程池最大值为10的情况下,第10个线程任务,并没有被创建出新线程去执行,
而是等待其他线程任务执行完毕,利用空闲线程开始任务

结论:在达到最大允许的线程数数量时,会停止创建新线程

00:00:10.8389135: Task 6 finished
00:00:10.8393725: Task 16 started

注意观察以上两波线程任务开始和结束的情况,都是相同数量的任务结束后,马上执行新任务(在达到最大线程数量的情况下)

结论:线程数量不足时,新任务会等待到空闲线程后立即执行

00:00:11.8383439: Task 7 finished
00:00:11.8384659: Task 17 started
00:00:12.8378835: Task 8 finished
00:00:12.8380083: Task 18 started
00:00:13.8357117: Task 9 finished
00:00:13.8363946: Task 19 started
00:00:20.1068402: Task 10 finished
00:00:20.1068384: Task 11 finished
00:00:20.1078310: Task 15 finished
00:00:20.1078314: Task 14 finished
00:00:20.1078460: Task 13 finished
00:00:20.1078566: Task 12 finished
00:00:20.8402527: Task 16 finished
00:00:21.8392482: Task 17 finished
00:00:22.8385449: Task 18 finished
00:00:23.8371386: Task 19 finished

标签:finished00,00,Task,started00,ThreadPool,API,线程,SetMinThreads,空闲
From: https://www.cnblogs.com/stevenduxiang/p/18150028

相关文章

  • APIView类
    【一】APIView类的介绍【1】介绍​ DjangoRESTFramework(DRF)中的APIView类是一个非常重要的基类,用于定义基于类的视图(Class-basedViews)来处理RESTfulAPI请求。它提供了强大的功能和灵活的扩展点,使得编写API视图变得更加简单和灵活。【2】主要特点和用法处理HTTP请......
  • Reddit采集API reddit文章评论和搜索 实时数据接口
    近期调研发现iDataRiver平台https://www.idatariver.com/zh-cn/提供开箱即用的Reddit数据采集API,是目前用下来最方便简单的API,可以抓取reddit公开数据,例如subreddit中的帖子、按关键字搜索以及文章评论等,供用户按需调用。接口使用详情请参考RedditAPI接口接口列表1.获......
  • fastapi
    FastAPI1.restful接口开发规范 2.quickstart async:表示函数内部可以使用异步 使程序可以直接运行,需要导入uvicornport:端口号,debug:开发模式,reload 3.路径操作路径指的是URL中从第一个/起的后半部分。例如:https://example.com/items/foo的路径是/items/foo......
  • [转帖]十年拉锯战终结束,Google 赢得 Java API 版权诉讼
    https://www.oschina.net/news/136073/googles-wins-lawsuit Google和Oracle(甲骨文)在法庭上就Android操作系统中Java编程语言的使用问题争吵了十年。美国最高法院在周一以6比2的投票结果裁定,Google对Java代码的使用被归为"合理使用",没有违反联邦版权法......
  • [转帖]Oracle 败了、谷歌赢了:Java API 版权案最终裁决
    https://zhuanlan.zhihu.com/p/362496136 周一,最高法院在Oracle围绕移动操作系统Android中所用软件的一起旷日持久的版权诉讼中判谷歌胜诉。法院的判决为6比2。大法官AmyConeyBarrett没有参与此案。该案涉及谷歌用于构建Android的12000行代码,这些代码是从SunMicrosy......
  • knife4j api文档使用说明
    1、引入依赖:<dependency><groupId>com.github.xiaoymin</groupId><artifactId>knife4j-openapi3-jakarta-spring-boot-starter</artifactId><version>4.5.0</version></d......
  • Apple App Store API 快速获取app综合评分,最新评论
    iDataRiver平台https://www.idatariver.com/zh-cn/提供开箱即用的苹果应用商城appstore数据采集API,供用户按需调用。接口使用详情请参考appleAppStore接口文档接口列表1.获取指定app的基础信息参数类型是否必填默认值示例值描述apikeystring是idr_***......
  • AXIOS的封装拦截以及API接口管理详解
    在我们做vue项目时,使用axios请求数据已经是司空见惯了,它是基于promise的http库,可以运行在浏览器和nodejs中,其实他有很多的优秀特性,例如,请求拦截,响应拦截,以及取消请求,json转换,客户端防御XSRF等,所以尤大大直接推荐我们使用axios库。我们先看axios如何封装,首先我在src下创建requestj......
  • IIS 部署WEBAPI
    ASP.NETCore不再是由IIS工作进程(w3wp.exe)托管,而是使用自托管Web服务器(Kestrel)运行,IIS则是作为反向代理的角色转发请求到Kestrel不同端口的ASP.NETCore程序中,随后就将接收到的请求推送至中间件管道中去,处理完你的请求和相关业务逻辑之后再将HTTP响应数据重新回写到IIS中,最终转达......
  • 比较RPC和RESTful API的优缺点
    RPC和RESTfulAPI是两种不同的远程调用方式,它们各自具有不同的优缺点。RPC的优点包括:高效:RPC使用自定义的通信协议,可以减少报文传输量,提高传输效率。灵活:RPC支持多种语言,不同的编程语言可以方便地调用远程接口。通用:RPC可以基于XML、JSON等标准化的数据格式进行通信,使得不同......