为什么Netty NioEventLoopGroup的线程数默认为CPU核心数_2?

结论:CPU的一个核心同一时间只能运行一个线程,考虑可能有线程会睡眠等待事件完成,另一个线程正好在此期间运行,CPU也不会空闲,所以CPU的核心数*2的线程数比较适合IO密集型操作

1、CPU运行逻辑

图灵机是计算机的最初概念,在一张无限长的纸带上有一个一个的方格,机器头在纸带上移动,读取方格中的信息,根据机器头存储的程序处理输出结果到方格上。其中涉及到存储程序、逻辑计算、输入、输出等功能。图灵机只是一个抽象的模型,而冯诺依曼提出了计算机的组成,这是现代计算机的基础,所以冯诺依曼被称之为现代计算机之父,而图灵被称之为计算机之父。

冯诺依曼体系结构:

  • 采用二进制为基础
  • 计算机是按照程序的指令顺序执行
  • 计算机由五部分组成:运算器、存储器、控制器、输入设备、输出设备

从计算机宏观角度来看CPU承担了运算器和控制器的作用,内存和硬盘承担存储器的作用,又由于二进制数基础,CPU执行的二进制指令。

为啥说从宏观角度?CPU内部也有这五部分组件,运算器 - 运算单元(ALU)、存储器 - 寄存器组(MU)、控制器 - 控制单元(CU)、输入输出 - 内部总线

CPU执行程序,程序又存储在内存,在单机的情况下CPU和内存是瓶颈。假设只有一个程序运行在CPU(单核)上,程序不会有延迟,也不会有瓶颈问题,顶多是内存不够用。但实际上,不可能只有一个程序,所以在多程序(任务)的情况下CPU如何运行?假设内存无限(不考虑内存瓶颈)

分布式情况下要加上IO瓶颈

假设三个任务A、B、C,CPU运行一秒,如何分配时间?

  • 一秒全部运行一个任务(串行)
  • 一秒拆分成N个时间片,三个任务交替执行(分时复用)

给出两个概念

  • 时延:一个任务从开始到结束的时间
  • 吞吐量:给定时间范围内,执行的任务数。比如TPS(一秒内执行的事务数)、QPS(一秒内执行的查询数)

两种情况各有优劣:

  • 优:被选中的任务无延迟(时延低);劣:其他任务无法执行(吞吐量低)
  • 优:所有任务都能执行(时延高);劣:所有任务延迟变高(吞吐量高)

在设计和开发中,两种情况都会遇到,我们称之为CPU密集型和IO密集型,

  • CPU密集型任务:编解码、加解密、数学计算等任务
  • IO密集型任务:网络请求、数据库、分布式网络等任务

注意:现代CPU都是时间片模式,第一种情况只是抽象,N个时间片都给一个任务使用,不就相当于一秒只执行一个任务么

2、进程(线程)切换

现在的计算机基本都是多CPU(或多核)模式,那么一个CPU同一时间只能运行一个任务。要运行其他任务如何进行切换的呢?

进程切换会以简洁的方式说明,具体的知识点会在后续文章详解

CPU执行的任务是由二进制组成,二进制输入,CPU逻辑处理,然后二进制输出。这跟什么很像?图灵机。CPU是机器头,任务指令是纸袋。计算机是按指令的顺序执行,一系列顺序的指令组成指令流(方法或函数)。

由于存储器材料和设计的不同,越靠近CPU的存储器访问速度越快,但价格也越贵,那么其容量也越小。容量从大到小排列(访问速度从慢到快)硬盘>内存>CPU缓存(L3>L2>L1)。硬盘是永久存储的,内存是掉电就失的,指令流最终肯定要存在永久存储的设备中。但访问速度会限制CPU的效率,需要将硬盘的指令流暂存到内存,再暂存到CPU缓存中。

CPU缓存无法存放完整的指令流,那么指令流就要放到内存或硬盘(代码帧),CPU操作指令流产生的数据为私有数据(栈帧)、CPU操作多指令流产生的数据为共享数据(堆栈帧)、无需通过CPU产生的数据为静态数据(数据帧)。一个任务有多个指令流,帧组合在一起形成段,即代码段、栈段、堆栈段、数据段。

img

指令流在CPU中执行,实际上就是与四个帧交互,为了加速CPU运行,需要将帧的元数据(描述信息)存储在CPU的存储单元(寄存器组)中。帧组成段,段组成任务(进程)。寄存器组存储任务的元数据。

段的元数据为啥不存储在缓存中?寄存器具有更快的访问速度,也可以进行权限校验。缓存中都是数据或指令。

程序之间要保持独立性,不能直接通过物理内存访问。Intel提出虚拟内存和特权级的概念。虚拟内存保证进程的隔离性,就是假定每个进程都拥有一整片内存,进程占用的空间可以很大(只要不超过CPU的位数(32位或64位),2^32 byte或2^64 byte)。特权级保证进程的安全性,用户进程特权级低于内存进程,不能随意访问,不然内核容易崩溃。

进程在CPU运行给定的时间,当时间片运行完需要切换到其他进程。这就需要时间机制来计算运行时间。再使用中断机制暂停当前运行的进程,切换到其他进程。

寄存器组存储进程的元数据,进程切换时要恢复下一个要运行的进程的元数据,那么原来的数据将被覆盖,此时就要在内存保存原先进程的元数据。Intel将保存寄存器组数据的段称之为任务段(TSS - Task State Segment)

虚拟内存是虚拟出来的,与物理内存不一样,CPU要将虚拟内存映射为物理内存。进程的不同,两者映射关系也不同。进程切换时也必须重新映射。

切换寄存器组就是进程的上下文切换。进程的上下文就是运行时的环境信息

说了这么多,进程切换的流程总结一下:

  • 时钟每一次滴答要触发中断,累计时钟滴答次数。判断当前运行进程时间片耗完时,选择下一个要运行的进程。
  • 触发中断暂停当前进程的运行,保存TSS段,加载新进程的TSS段
  • 切换特权级,重新映射新进程的虚拟内存与物理内存的关系
  • 旧进程缓存的数据也要更新

由此可见进程切换需要很多操作

3、CPU密集型和IO密集型

CPU密集型主要是依赖于CPU性能的任务,会涉及到大量的计算操作、数据处理、逻辑运算等。进程数一般为CPU的核心数,正好一个核心执行一个进程,能最大程度利用CPU的性能。若进程数多于CPU核心数,需要耗费一些性能用于进程切换。反之进程数少于CPU核心数,又不能充分利用CPU。

IO密集型主要是依赖于输入输出(I/O)的任务。涉及磁盘、网络、数据库等外部设备或资源。进程数一般为CPU核心数的两倍,也就是一个CPU核心管理两个进程。假定一个进程由于访问外部资源时无法立即获取反馈,进程可能处于阻塞状态,那么CPU要切换到另一个进程执行。这样可以不让CPU歇着,一直处理业务进程。为啥进程数不能为CPU核心数的两倍以上?还是由于进程切换耗费性能,而频繁的切换会进一步导致性能下降。

Netty的NioEventLoopGroup明显是IO密集型,进程数更适合为CPU核心数的两倍

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值