CPU 的上下文切换简单理解

摘要:CPU 是什么,CPU 的工作原理,CPU 缓存,CPU 的上下文切换,为什么要避免 CPU 的上下文切换,CPU 的主要瓶颈主要是什么。

CPU 是什么?

中央处理器 Central Processing Unit,简称 CPU。如果把计算机比作人的话,那么 CPU 就是人的大脑。具体定义,请自行 Google 一下。


CPU 中是什么

CPU 中主要有三部分:运算器、控制器、寄存器。


CPU 的基本工作原理

CPU 是和内存配合工作,每次都会从内存中获取指令然后进行处理。内存中主要存放两部分:程序(指令)、数据。

CPU 的工作就是逐条加载内存中二进制指令流,基本上就是在取指令、分析指令、执行指令,周而复始的运作。详细工作分为以下 5 个阶段:取指令阶段、指令译码阶段、执行指令阶段、访存取数和结果写回。

第一阶段:取指令(IF,instruction fetch)即将一条指令从内存中取到指令寄存器的过程。程序计数器中的数值,用来指示当前指令在主存中的位置。当 一条指令被取出后,计算机中的数值将根据指令字长度自动递增。

第二阶段:指令译码阶段(ID,instruction decode)取出指令后,指令译码器按照预定的指令格式,对取回的指令进行拆分和解释,识别区分出不同的指令类 别以及各种获取操作数的方法。

第三阶段:执行指令阶段(EX,execute)具体实现指令的功能。CPU 的不同部分被连接起来,以执行所需的操作。

第四阶段:访存取数阶段(MEM,memory)根据指令需要访问主存、读取操作数,CPU 得到操作数在主存中的地址,并从主存中读取该操作数用于运算。部分指令不需要访问主存,则可以跳过该阶段。

第五阶段:结果写回阶段(WB,write back)作为最后一个阶段,结果写回阶段把执行指令阶段的运行结果数据“写回”到某种存储形式。结果数据一般会被写到 CPU 的内部寄存器中,以便被后续的指令快速地存取;许多指令还会改变程序状态字寄存器中标志位的状态,这些标志位标识着不同的操作结果,可被用来影响程序的动作。

在指令执行完毕、结果数据写回之后,若无意外事件(如结果溢出等)发生,计算机就从程序计数器中取得下一条指令地址,开始新一轮的循环,下一个指令周期将顺序取出下一条指令。


CPU 缓存

用于减少 cpu 访问内存所需时间,当处理器发出内存访问请求时,会先查看缓存内是否有请求数据。如果存在(命中),则不经访问内存直接返回该数据,如果不存在(失效),则要先把内存中的相应数据载入缓存,再将其返回处理器。

CPU 缓存的容量比内存小的多但是交换速度却比内存要快得多。缓存的出现主要是为了解决 CPU 运算速度与内存读写速度不匹配的矛盾,因为 CPU 运算速度要比内存读写速度快很多,这样会使 CPU 花费很长时间等待数据到来或把数据写入内存。CPU 缓存和 CPU 一般是同频运作,工作效率远高于内存和硬盘。缓存容量的增大也会有提升 CPU 的命中率,而不用到内存或者硬盘上寻找,从此提高系统性能。

CPU 缓存一般分为一级缓存、二级缓存,部分高端的 CPU 还有三级缓存,每一级缓存所存储的全部数据都是下一级缓存的一部分,比如一级缓存存储了 1 - 10 个数字,二级缓存可能会存储 1 - 15 个数字,三级缓存会存储 1 - 20 个数字。三种缓存的技术难度和制造成本是相对递减的,所以容量是相对递增的。一般来说,每级缓存的命中率都是 80% 左右,也就是全部数据量的 80% 可以从一级缓存中获取,只剩下20%的总数据量才需要从二级缓存、三级缓存或内存中读取,由此可见一级缓存是整个 CPU 缓存架构中最为重要的部分。

CPU 要读取一个数据时,首先从 CPU 缓存中查找,如果找到就立即读取并送给 CPU 处理。如果没有找到,就从内存中读取并送给 cpu 处理,同时把这个数据所在的数据块存入 CPU 缓存中,可以使得以后对整块数据的读取都从 CPU 缓存中查找,不必再调用内存。

总结就是 CPU 缓存越大越好,级别越多越好。


CPU 的上下文切换

上下文切换,有时也称做进程切换或任务切换,我们可以理解成 CPU 从一个进程或线程切换到另一个进程或线程,但是这个切换的过程中,我们要将之前的任务保存起来,然后再去运行新的任务,这些保存起来的任务会存在 CPU 的内核中,并在任务重新调度执行时再次加载进来,这样就能保证原来的任务不受影响,让任务看起来是连续运行的。

所以在操作系统中 CPU 从一个进程切换到另外一个进程需要保存当前进程的状态并恢复另一个进程的状态。从这个角度来看,上下文切换有点像我们同时阅读几本书,在来回切换书本的同时我们需要记住每本书当前读到的页码。

上下文切换通常是计算密集型的。也就是说,它需要相当可观的处理器时间,在每秒几十上百次的切换中,每次切换都需要纳秒量级的时间。所以,上下文切换对系统来说意味着消耗大量的 CPU 时间,事实上,可能是操作系统中时间消耗最大的操作,并会对性能造成负面影响。


CPU 的跨核上下文切换

如果说 CPU 上下文切换会对性能造成负面影响,那么影响中更昂贵的上下文切换是跨核上下文切换(Cross-Core Context Switch)。

一个线程可以运行在一个专用处理器上,也可以跨处理器。由单个处理器服务的线程都有处理器关联(Processor Affinity),这样会更加有效。在另一个处理器内核抢占和调度线程会引起缓存丢失,作为缓存丢失和过度上下文切换的结果要访问本地内存。本来可以在自己关联的处理器上就可以完成,还可以使用当前处理器的缓存,但如果跨核切换,就会导致缓存丢失,还要去访问内存。


为什么要避免 CPU 的上下文切换

CPU 的上下文切换计算是密集型的,每次上下文切换都需要消耗时间,也可能是操作系统中时间消耗最大的操作,并会对程序造成负面影响。那么 CPU 跨核上下文切换就更严重,会直接导致 CPU 缓存失效,让 CPU 直接访问内存。

所以 Nginx 要开启和 CPU 核数相等的 Worker 进程,最好要把 Worker 进程绑定到 CPU 上,防止 CPU 跨核切换导致 CPU 缓存失效。


Linux 的 CPU 监控命令

vmstat 命令查看系统上下文切换情况

[root@localhost ~]# vmstat 1
procs -----------memory---------- ---swap-- -----io---- -system-- ------cpu-----
 r  b   swpd   free   buff  cache   si   so    bi    bo   in   cs us sy id wa st
 3  0   5640 153428      0 410608    0    0    19     5   59   94  0  0 99  0  0
 0  0   5640 153428      0 410608    0    0     0     0   46   95  0  1 99  0  0
 0  0   5640 153428      0 410608    0    0     0     0   41   90  0  0 100  0  0

pidstat 命令是 sysstat 性能监控工具套件,如果没有 pidstat 可以先 yum install sysstat,这些工具可以监控系统性能的使用情况。各工具的作用如下:

[root@localhost ~]# pidstat -u -w 1
Linux 3.10.0-957.27.2.el7.x86_64 (localhost)    xxxx年xx月xx日  _x86_64_        (1 CPU)

03时52分56秒   UID       PID    %usr %system  %guest    %CPU   CPU  Command
03时52分57秒     0      5606    0.00    1.96    0.00    1.96     0  pidstat

03时52分56秒   UID       PID   cswch/s nvcswch/s  Command
03时52分57秒     0         3      1.96      0.00  ksoftirqd/0
03时52分57秒     0         9      3.92      0.00  rcu_sched
03时52分57秒     0      1483      0.98      0.00  php-fpm
03时52分57秒     0      2032      0.98      0.00  kworker/u128:2
03时52分57秒     0      5604      0.98      0.00  kworker/0:0
03时52分57秒     0      5606      0.98      0.98  pidstat


参考资料:

性能瓶颈--CPU(上下文切换)

程序优化:CPU缓存基础知识

一文让你明白CPU上下文切换

利用cpu缓存实现高性能程序

结束语:感谢您对本网站文章的浏览,欢迎您的分享和转载,但转载请说明文章出处。
Top