zoukankan      html  css  js  c++  java
  • 线程池如何更好的使用

    前言

      对于如何更合适的使用线程池,根据系统业务是CPU密集型 还是IO密集型。

    cpu密集型:
        cpu使用率较高(也就是一些复杂运算,逻辑处理),所以线程数一般只需要cpu核数的线程就可以了。 这一类型的在开发中多出现的一些业务复杂计算和逻辑处理过程中。

    I/O密集型:
           cpu使用率较低,程序中会存在大量I/O操作占据时间,导致线程空余时间出来,所以通常就需要开cpu核数的两倍的线程, 当线程进行I/O操作cpu空暇时启用其他线程继续使用cpu,提高cpu使用率 通过上述可以总结出:

      线程的最佳数量: 最佳线程数目 = ((线程等待时间+线程CPU时间)/线程CPU时间 )* CPU数目

      线程等待时间所占比例越高,需要越多线程。线程CPU时间所占比例越高,需要越少线程。这一类型在开发中主要出现在一些读写操作频繁的业务逻辑中。

      --------------------------------------------------------------------------------------------------------------

           开发中我们经常会使用到线程池来处理一些业务,而在不新增设备的情况下,我们所能使用的线程资源又不是无线的,那么高并发、任务执行时间短的业务怎样使用线程池?还有并发不高、任务执行时间长的业务怎样使用线程池?并发高、业务执行时间长的业务怎样使用线程池?

    接下来我们进行一一分析:

    1:高并发、任务执行时间短的业务,线程池线程数可以设置为CPU核数+1,减少线程上下文的切换

    2:并发不高、任务执行时间长的业务这就需要区分开看了:

    a)假如是业务时间长集中在IO操作上,也就是IO密集型的任务,因为IO操作并不占用CPU,所以不要让所有的CPU闲下来,可以适当加大线程池中的线程数目,让CPU处理更多的业务

    b)假如是业务时间长集中在计算操作上,也就是计算密集型任务,这个就没办法了,和(1)一样吧,线程池中的线程数设置得少一些,减少线程上下文的切换

    (其实从一二可以看出无论并发高不高,对于业务中是否是cpu密集还是I/O密集的判断都是需要的当前前提是你需要优化性能的前提下)

    3:并发高、业务执行时间长,解决这种类型任务的关键不在于线程池而在于整体架构的设计,看看这些业务里面某些数据是否能做缓存是第一步,我们的项目使用的时redis作为缓存(这类非关系型数据库还是挺好的)。增加服务器是第二步(一般政府项目的首先,因为不用对项目技术做大改动,求一个稳,但前提是资金充足),至于线程池的设置,设置参考 2 。最后,业务执行时间长的问题,也可能需要分析一下,看看能不能使用中间件(任务时间过长的可以考虑拆分逻辑放入队列等操作)对任务进行拆分和解耦。

       --------------------------------------------------------------------------------------------------------------

    ThreadPoolExecutor参数设计

       我们知道通过Executors的静态方法创建不同种类线程池,但实质都是传递不同参数给ThreadPoolExecutor的构造方法。corePooleSize、maxPoolSize、BlockingQueue之间的关系和线程池创建的过程就不说了,下面简单说他们的关系,详情看个人的其他文章。

    • corePoolSize是核心线程数,maxPoolSize是最大线程数,BlockingQueue是任务队列
    • 当有任务提交时,先创建corePoolSize数量的线程,有更多的任务则进入到BlockingQueue,BlockingQueue满了还不够则创建线程数直到macPoolSize
    • 线程空闲一段时间后会被销毁直到线程池中只剩下core数量的线程

    如何设计这些参数值呢?

    通过例子来说明:

    1. 假如提交到线程池中的任务,IO耗时占比是80%,计算耗时占比20%,忽略提交到线程池中的任务数量,在4C8G的机器上,理想情况下线程池中创建多少个线程是最优的?

      线程数=(1/0.2) * 4 = 20

    2. 假如e有一类cpu密集性的任务,没有IO操作,日常的时候只有1个任务,流量高峰会有50个任务,4C8G的机器上,使用的线程池,如何设置corePoolSize, maxPoolSize以及BlockingQueue的大小?

     回答1:core=4, max=50, queue=1w。maxPoolSize数量的线程永远不会被创建,队列设置成1w,这个队列太大,根本就不会满。这样是不理想的 造成资源的浪费。

      日常每秒1个任务时,只需要一个线程就够了,创建出4个线程,就有3个浪费。

     回答2:

      很显然,日常只需要一个线程,那么corePoolSize=1,而高峰时候,虽然任务有50个,但是只是4C的机器,对于cpu密集型任务,4个线程是最优的,因此理想情况下maxCorePoolSize=4,最后再看看队列,因为队列满了,max才会被创建,而我们需要让max快速被创建出来,又不会出现任务拒绝,因此,可将队列大小设置成46,那么线程池的行为如下:

    • 提交第一个任务,创建出core,1个线程
    • 提交第二个到第47个任务时,这些任务进入到队列中,此时队列已满
    • 提交第48个任务到第50个任务时,创建出max,此时一共有4个线程
    • 4个线程同时将队列里的46个任务消费完
    • 一段时间后,max - core数量的线程销毁,即销毁3个线程,还剩下一个线程

    参考:https://zhuanlan.zhihu.com/p/86433815

  • 相关阅读:
    【FFMPEG】Ubuntu上安装FFMPEG
    【FFMPEG】Ubuntu上安装FFMPEG
    【FFMPEG】FFMPEG介绍
    【FFMPEG】FFMPEG介绍
    【并行计算-CUDA开发】 NVIDIA Jetson TX1
    【并行计算-CUDA开发】 NVIDIA Jetson TX1
    【ARM-Linux开发】【DSP开发】AM5728介绍
    【ARM-Linux开发】【DSP开发】AM5728介绍
    【FFMPEG】ffmpeg 中添加264支持
    【FFMPEG】ffmpeg 中添加264支持
  • 原文地址:https://www.cnblogs.com/FondWang/p/12457450.html
Copyright © 2011-2022 走看看