关于CPU原理、CPU核数、线程、线程池、线程池大小的研究分析

    一CPU

    1.1CPU内核、核数、核心线程、多核、物理核、逻辑核

      CPU内核就是说的单核CPU、多核CPU的核,首先它是一个物理单位。有时候也把内核成为CPU,比如你的电脑有几个CPU,有时候指的就是你的电脑是几核。

     一般来说,单核配单线程、双核配双线程或者双核四线程、四核八线程等等

     理论上来说,核心数越多,干活的效率越高,或者说可以同时干的事情越多,就像一个工厂,这个车间可以生产这个零部件,那个车间可以生产另外一个零部件。

     CPU工作过程快,一个CPU的核心在处理一个线程的时候,如果这个线程过程中需要等待IO,在等待的过程中,核心去执行另一个线程。那么这样在一段时间内,CPU同时服务了两个线程,一个物理核心就变成了两个逻辑核心,即单核CPU成了双核。

     1.2CPU主频、频率、倍频、外频

       刚才提到一个CPU工作过程快,一段时间内处理多个线程,实现了逻辑多核,这个快慢就是由频率决定的。

       CPU 的频率简单说是 CPU 运算时的工作频率(CPU 内部的数字时钟信号频率),是单位时间1 S 内产生的脉冲信号个数。

         CPU有自己的频率,CPU和外设沟通的时候,外设也有自己的频率。CPU的频率高,外设的频率低,为了CPU和外设进行更好的沟通,,Intel 就创造性的提出了倍频 的概念,让 CPU 频率运行在外频的某个倍率上,这样频率较高的 CPU 就能和较低的外频进行同步交流了。

      我们平时提到的主频就是CPU的频率。

         主频 = 倍频 * 外频

       这里提一句,CPU并不是频率越高越好,需要考虑到耗能等其他问题。

       1.3CPU内核组成、运算器、控制器、总线

   从结构上讲 CPU 内核分为两部分:运算器和控制器。

  简单的理解,运算器就是内核计算的部分,计算加减乘除和位移运算等。运算器又分为运算单元和寄存器(组),运算单位进行最小单位的运算,寄存器(组)用于存储计算过程中产生的数据。

  控制器厉害了,它可以调度运算器和外设。比如指令控制器,它负责给运算器分配任务(指令)、时序控制器控制上文提到的倍频。总线控制器控制CPU 的内外部总线,包括地址总线、数据总线、控制总线等等。中断控制器用于控制各种各样的中断请求,并根据优先级的高低对中断请求进行排队,逐个交给 CPU 处理。

  总线(Bus),是指计算机设备和设备之间传输信息的公共数据通道。总线是连接计算机硬件系统内多种设备的通信线路,它的一个重要特征是由总线上的所有设备共享,可以将计算机系统内的多种设备连接到总线上。微机中的总线分为数据总线、地址总线和控制总线3类。不同型号的CPU芯片,其数据总线、地址总线和控制总线的条数可能不同。

         二多线程

    2.1线程、线程和CPU的关系、多线程

  首先大家都应该知道什么是进程,进程和线程的关系。简单说进程就是一个程序要去做事情,做这个事情需要分几步,每一步就是线程,这里的步是最小单位,就是不能再分了。而且有可能有几步是可以同时执行的,这就是多线程。

线程(英语:thread)是操作系统能够进行运算调度的最小单位。线程是独立调度和分派的基本单位。

线程和cpu的关系。这里的CPU就是指的CPU内核。古时候,一个CPU在同一时间只能处理一个线程,即使线程去吃喝拉撒了,在等待IO,等待厨师做饭的时候,线程什么也不做,CPU也闲着什么也不做。这就是单CPU单线程时代。后来,就像上文提到的,当线程等待IO、等待厨师做饭的时候,CPU可以去服务其他线程。这就是CPU多任务时代。再后来,一个CPU可以装多个内核,每个内核可以执行多个任务,这就是多CPU多任务时代。

       2.2JAVA线程池、吞吐量、线程池的大小

   这里先声明一个前提,本文是基于Java开发写的,一切的概念都是JAVA里面或者和JAVA相关的。比如马上要讲的线程池,就是JAVA里的线程池。

      2.2.1线程池

  简单的讲,它是一个池子,池子是用来存水的,水指的就是线程,线程池就是用来存线程的。更明确的讲,线程池用来是存执行线程的命令。比如A向执行个线程,通知给线程池,B也要执行个线程,也通知给线程池。线程池把这些命令存起来。然后管理这些命令,在合理的时候,告诉哪条命令,好了你去执行线程吧。执行完就把这个命令从池子里拿出去。池子里的命令都是可以执行的。CPU没有资源的时候,告诉线程命令,你们先等等,池子满了,池子上面有个房子,你们先住着。等池子里有空了,你们再进来。当房子也满了,又有通知命令来了,线程池算了算,虽然池子满了,但是CPU还能扛得住,那么你先去执行吧。如果还有命令通知来,线程池实在解决不了了,就不接收了,或者说拒绝,哪儿来哪儿去,等有地了再来,这是在外面的表现就是你的电脑卡死了。

  在一个应用程序中,我们需要多次使用线程,也就意味着,我们需要多次创建并销毁线程。而创建并销毁线程的过程势必会消耗内存。而在Java中,内存资源是及其宝贵的,所以,我们就提出了线程池的概念。线程池的好处,就是可以方便的管理线程,也可以减少内存的消耗。

  线程池有几个概念,核心线程数corePoolSize,最大线程数maximumPoolSize,等待队列workQueue。线程工厂threadFactory。拒绝策略handler。

  线程池的执行过程:任务进来时,首先执行判断,判断核心线程是否处于空闲状态,如果不是,核心线程就先就执行任务,如果核心线程已满,则判断任务队列是否有地方存放该任务,若果有,就将任务保存在任务队列中,等待执行,如果满了,在判断最大可容纳的线程数,如果没有超出这个数量,就开创非核心线程执行任务,如果超出了,就调用handler实现拒绝策略。

    2.2.2吞吐量

  顾名思义吐下去和吐出来的数量,然后我们再加个条件单位时间。就是单位时间吐下去和吐出来的数量。

  吞下去,就是吞下去一个线程,就是线程来了去执行,吐出来,就是吐出一个线程,线程执行完了吐出去。

  比如,有一个线程执行完需要10秒,其他只需要1秒是计算服务,9秒是等待IO。那么来了这么10个线程。CPU先执行第一个,第一个执行完1秒后,剩下9秒就不管它了,再执行第二个线程,同样的到里,刚到执行到第10个的时候,第一个线程等到IO,那么第一个线程执行结束了。

  再比如,执行上面线程的时候,来了第11个线程,那么因为第11个线程来的时候,第一个已经执行完了,所以第11线程即使来了,也没什么好处,它不如去其他CPU看看。

  这时候我们可以简单理解吞吐量,10秒的情况下,可以最多接收10个线程,并且执行完1个线程。如果要计算1秒的吞吐量呢。有个公式

throughput = 10 tasks / (10 * computing time + wait time) 
           = 10 tasks / (10 * 1s + 9s) 
           = 10 / 19s = 0.526 tasks/s

  即1秒可以执行完0.526个任务。

  解释下这个公式,10个线程,完成需要19秒,吞吐量10/19

  再比如,还是上面的任务,这时候有两个CPU(内核),那么吞吐量是多少呢。乘以2吗,不是的。还是10个线程来了,我这时候可以同时执行两个线程,当第5秒的时候,10个线程的计算任务就都执行完了,但是这时候第一个线程还需要5秒才能结束等待。

  这时候吞吐量计算是10个线程除以5秒+9秒。即10/(5+9)=0.7142。吞吐量比一个CPU的时候大了。

  如果更多CPU呢。

  公式总结如下;

  数学好的算出来的,不是我算出来的。

  • Throughput:吞吐量。
  • Tn:task数量。
  • C:CPU数量。可以有小数,比如0.5,代表只提供一半的算力。
  • Tc:task计算所花费的时间。
  • Tw:task等待花费的时间。
  • E:最后一个task完成所消耗的时间。

   然后总结一句话,不看公式也知道,要提高吞吐量,CPU越多越好,线程的计算时间(计算的那1秒)越短越好。

  图是这样的,别人画的

     2.2.3线程池的大小

  在CPU数量和线程计算时间确定的情况,即针对一种线程(你明白的),吞吐量的确定情况下,线程池要设计多大呢。

  线程池容量=CPU数量*(计算时间+等待时间)/计算时间。

   这里默认CPU的利用率的百分百,即1。

   解释下,用上面的例子,一个线程计算时间+等待时间是10秒,计算时间是1秒,那么它的线程池的容量应该为10*CPU数量。跟我们刚才算的正好,如果只有1个CPU的话,那么来第11个没有意义,10个刚刚好。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值