操作系统--CPU高级

1.现代 CPU 架构

操作系统--CPU高级_第1张图片


2.CPU 读写单位

CPU Cache Line 是 CPU 从内存读取数据到 Cache 的单位。CPU Cache Line 大小一般是 64 个字节,也就意味着 CPU 读写数据的时候,每一次都是以 64 字节大小为一块进行操作。


3.CPU 伪共享问题

因为多个线程同时读写同一个 Cache Line 的不同普通变量时,而导致 CPU Cache 失效的现象称为伪共享(False Sharing

在 Linux 内核中存在 __cacheline_aligned_in_smp 宏定义,使得变量在 Cache Line 里是对齐的

操作系统--CPU高级_第2张图片     操作系统--CPU高级_第3张图片

为了防止前面提到的 Cache 伪共享问题,我们可以使用上面介绍的宏定义,将 b 的地址设置为 Cache Line 对齐地址,这样 a 和 b 变量就不会在同一个 Cache Line 中了。

所以,避免 Cache 伪共享实际上是用空间换时间的思想,浪费一部分 Cache 空间,从而换来性能的提升。

应用层面:Java 并发框架 Disruptor 使用「字节填充 + 继承」的方式

根据 JVM 对象继承关系中父类成员和子类成员,内存地址是连续排列布局的,因此 RingBufferPad 中的 7 个 long 类型数据作为 Cache Line 前置填充,而 RingBuffer 中的 7 个 long 类型数据则作为 Cache Line 后置填充,这 14 个 long 变量没有任何实际用途,更不会对它们进行读写操作。

操作系统--CPU高级_第4张图片

另外,RingBufferFelds 里面定义的这些变量都是 final 修饰的,意味着第一次加载之后不会再修改, 又由于「前后」各填充了 7 个不会被读写的 long 类型变量,所以无论怎么加载 Cache Line,这整个 Cache Line 里都没有会发生更新操作的数据,于是只要数据被频繁地读取访问,就自然没有数据被换出 Cache 的可能,也因此不会产生伪共享的问题


4.CPU 选择线程

任务是 进程、线程 (= 轻量级进程)、主线程 的统称。

在 Linux 系统中,根据任务的优先级以及响应要求,主要分为两种,其中优先级的数值越小,优先级越高:

  • 实时任务,对系统的响应时间要求很高,要尽可能快的执行实时任务,优先级在 0~99 范围内;
  • 普通任务,响应时间没有很高的要求,优先级在 100~139 范围内;

由于任务有优先级之分,Linux 系统为了保障高优先级的任务能够尽可能早的被执行,于是分为了这几种调度类,如下图:

操作系统--CPU高级_第5张图片

Deadline 和 Realtime 这两个调度类是应用于实时任务的,这两个调度类的调度策略如下:

  • SCHED_DEADLINE:是按照 deadline 进行调度的,距离当前时间点最近的 deadline 的任务会被优先调度;
  • SCHED_FIFO:对于相同优先级的任务,按先来先服务的原则,但是优先级更高的任务,可以抢占低优先级的任务,也就是优先级高的可以「插队」;
  • SCHED_RR:对于相同优先级的任务,轮流着运行,每个任务都有一定的时间片,当用完时间片的任务会被放到队列尾部,以保证相同优先级任务的公平性,但是高优先级的任务依然可以抢占低优先级的任务;

而Fair 调度类是应用于普通任务,都是由 CFS 调度器管理的,分为两种调度策略:

  • SCHED_NORMAL:普通任务使用的调度策略;
  • SCHED_BATCH:后台任务的调度策略,不和终端进行交互,因此在不影响其他需要交互的任务,可以适当降低它的优先级。

普通任务在 Linux 里面,实现了一个基于 CFS 的调度算法,也就是完全公平调度

  1. 这个算法的理念是想让分配给每个任务的 CPU 时间是一样,于是它为每个任务安排一个虚拟运行时间 vruntime,如果一个任务在运行,其运行的越久,该任务的 vruntime 自然就会越大,而没有被运行的任务,vruntime 是不会变化的。
  2. 在 CFS 算法调度的时候,会优先选择 vruntime 少的任务,以保证每个任务的公平性。
  3. 但是普通任务之间还是有优先级区分的,所以在计算虚拟运行时间 vruntime 还要考虑普通任务的权重值,注意权重值并不是优先级的值,内核中会有一个 nice 级别与权重值的转换表,nice 级别越低的权重值就越大。


5.CPU 运行队列

操作系统--CPU高级_第6张图片

这几种调度类是有优先级的,优先级如下:Deadline > Realtime > Fair,这意味着 Linux 选择下一个任务执行的时候,会按照此优先级顺序进行选择,也就是说先从 dl_rq 里选择任务,然后从 rt_rq 里选择任务,最后从 cfs_rq 里选择任务。因此,实时任务总是会比普通任务优先被执行

调整优先级

如果我们启动任务的时候,没有特意去指定优先级的话,默认情况下都是普通任务,普通任务的调度类是 Fair,由 CFS 调度器来进行管理。CFS 调度器的目的是实现任务运行的公平性,也就是保障每个任务的运行的时间是差不多的。

如果你想让某个普通任务有更多的执行时间,可以调整任务的 nice 值,从而让优先级高一些的任务执行更多时间。nice 的值能设置的范围是 -20~19, 值越低,表明优先级越高,因此 -20 是最高优先级,19 则是最低优先级,默认优先级是 0。


6.参考

小林 coding

你可能感兴趣的:(操作系统学习记录,linux)