CPU-bound(计算密集型) 和 I/O bound(I/O密集型)

如果所有的任务都是计算(CPU)密集型的,则创建处理器可用核心数这么多个线程就可以了,这样已经充分利用了处理器,也就是让它以最大火力不停进行计算。创建更多的线程对于程序性能反而是不利的,因为多个线程间频繁进行上下文切换对于程序性能损耗较大。线程数=cpu核心数+1

    但如果任务都是IO密集型的,那我们就需要创建比处理器核心数大几倍数量的线程。为何?当一个任务执行IO操作时,线程将被阻塞,于是处理器可以立即进行上下文切换以便处理其他就绪线程。如果我们只有处理器核心数那么多个线程的话,即使有待执行的任务也无法调度处理了。线程数=cpu核心数/(1-阻塞系数)。一般这时候的线程数是cpu核心数的好几倍。以便于线程发生I/O阻塞时cpu有可以进行线程上下文切换的线程。

 

 

如何设置线程数大小

要想合理的配置线程池,就必须首先分析任务特性,可以从以下几个角度来进行分析:

  1. 任务的性质:CPU密集型任务,IO密集型任务和混合型任务。

    (1)CPU密集型任务配置尽可能小的线程,如配置Ncpu+1个线程的线程池。

    (2)IO密集型任务则由于线程并不是一直在执行任务,则配置尽可能多的线程,如2*Ncpu。

    (3)混合型的任务,如果可以拆分,则将其拆分成一个CPU密集型任务和一个IO密集型任务,只要这两个任务执行的时间相差不是太大,那么分解后执行的吞吐率要高于串行执行的吞吐率,如果这两个任务执行时间相差太大,则没必要进行分解。我们可以通过Runtime.getRuntime().availableProcessors()方法获得当前设备的CPU个数。

  2. 任务的优先级:高,中和低。

    优先级不同的任务可以使用优先级队列PriorityBlockingQueue来处理。它可以让优先级高的任务先得到执行,需要注意的是如果一直有优先级高的任务提交到队列里,那么优先级低的任务可能永远不能执行。

  3. 任务的执行时间:长,中和短。
    执行时间不同的任务可以交给不同规模的线程池来处理,或者也可以使用优先级队列,让执行时间短的任务先执行。
  4. 任务的依赖性:是否依赖其他系统资源,如数据库连接。
    依赖数据库连接池的任务,因为线程提交SQL后需要等待数据库返回结果,如果等待的时间越长CPU空闲时间就越长,那么线程数应该设置越大,这样才能更好的利用CPU。

补充:调节线程池大小的另一种方法如下

给定以下定义:

Ncpu:CPU的数量(Runtime.getRuntime().availableProcessors()方法获得当前设备的CPU个数)

Ucpu:target CPU utilization ,1 <= Ucpu <= 1

W/C:W为任务的等待时间,C为任务的运行时间

要使处理器达到期望的使用率,线程池的最优大小为:Ncpu * Ucpu * (1  + W/C)

 

 

 

IO密集型应用 - 阻塞系数大,建议多一点的线程数 - 建议为2倍CPU数,即假设等待时间和线程CPU时间一样,阻塞系数为0.5 

 

CPU计算密集型应用 - 线程等待时间少,建议少一点的线程数 - 一般建议为CPU数,即假设线程等待时间为0,阻塞系数为0 

 

 

最佳线程数 cpu数/1-阻塞系数

 

阻塞系数 线程等待时间/ 线程等待时间 + 线程CPU时间 

CPU-bound(计算密集型) 和 I/O bound(I/O密集型)

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值