由于近期工作需要,最近需要测试开发某组件(该组件中用到了ThreadPoolExecutor)的性能,测试工具是soapUI,由于以前对测试性能方面接触较少。所以借此机会再网上查阅了相关资料,总结如下。
其中一种说法,是线程数和cpu数有关系。
总体意思是,当应用是IO密集型时,线程数T=2N+1.
当应用是CPU密集型时, 线程数T=N+1
T=线程数 N=cpu逻辑盒数
IO密集型应用:系统的CPU性能相对硬盘、内存要好很多,大部分的情况是CPU在等I/O (硬盘/内存) 的读/写操作,此时 CPU Loading并不高。
CPU密集型应用:系统的硬盘、内存性能相对CPU要好很多,CPU要读/写I/O(硬盘/内存),I/O在很短的时间就可以完 成,而CPU还有许多运算要处理,CPU Loading很高。
如果上面对IO和CPU密集型应用解释不好理解,简单讲如果你的应用大部分是I/O读写操作,很少复杂高频的运算,cpu 大部分是等待I/O运算,那么你的应用就是IO密集型应用;如果你的应用很少读写操作,基本都是高频且复杂的各种运算,cpu大部分时间都很忙,那么你的应用是CPU密集型应用。一般情况我们的应用都是I/O密集型应用。
另外一种说法,是ThreadPoolExecutor线程池设置和实际并发量有关系。
1、先简单说下线程池ThreadPoolExecutor的几个参数的意思:
corePoolSize:核心线程数
核心线程会一直存活,及时没有任务需要执行
当线程数小于核心线程数时,即使有线程空闲,线程池也会优先创建新线程处理
设置allowCoreThreadTimeout=true(默认false)时,核心线程会超时关闭
queueCapacity:任务队列容量(阻塞队列)
当核心线程数达到最大时,新任务会放在队列中排队等待执行
maxPoolSize:最大线程数
当线程数>=corePoolSize,且任务队列已满时。线程池会创建新线程来处理任务
当线程数=maxPoolSize,且任务队列已满时,线程池会拒绝处理任务而抛出异常
keepAliveTime:线程空闲时间
当线程空闲时间达到keepAliveTime时,线程会退出,直到线程数量=corePoolSize
如果allowCoreThreadTimeout=true,则会直到线程数量=0
allowCoreThreadTimeout:为true时允许核心线程超时,即核心线程空闲时间超时也可以退出
rejectedExecutionHandler:任务拒绝处理器
ThreadPoolExecutor执行顺序:
当线程数小于核心线程数时,来了新任务就创建新线程,即使有空闲线程。
当线程数大于等于核心线程数,且任务队列未满时,将任务放入任务队列。
当线程数大于等于核心线程数,且任务队列已满
若线程数小于最大线程数,创建线程
若线程数等于最大线程数,抛出异常,拒绝任务
2、再说下如何设置线程池的参数,需要根据几个值来决定。
tasks :每秒的任务并发数,假设为500~1000
taskcost:每个任务花费时间,假设为0.1s(可以依据soapUI的平均时间avg参数)
responsetime:系统允许容忍的最大响应时间,假设为1s
做几个计算
corePoolSize = 每秒需要多少个线程处理?
threadcount = tasks/(1/taskcost) =tasks*taskcout = (500~1000)*0.1 = 50~100 个线程。corePoolSize设置应该大于50
根据8020原则,如果80%的每秒任务数小于800,那么corePoolSize设置为80即可
queueCapacity = (coreSizePool/taskcost)*responsetime
计算可得 queueCapacity = 80/0.1*1 = 80。意思是队列里的线程可以等待1s,超过了的需要新开线程来执行
切记不能设置为Integer.MAX_VALUE,这样队列会很大,线程数只会保持在corePoolSize大小,当任务陡增时,不能新 开线程来执行,响应时间会随之陡增。
maxPoolSize = (max(tasks)- queueCapacity)/(1/taskcost)
计算可得 maxPoolSize = (1000-80)/10 = 92
(最大任务数-队列容量)/每个线程每秒处理能力 = 最大线程数
rejectedExecutionHandler:根据具体情况来决定,任务不重要可丢弃,任务重要则要利用一些缓冲机制来处理
keepAliveTime和allowCoreThreadTimeout采用默认通常能满足
假如并发量在50-150之间,我的线程执行时间大概是5ms左右,tps在65-200,cpu使用率在30%-70%,这个数据就不是很理想。当然这些测试是在本地笔记本并非服务器上。