1 缓存一致性
数据写入怎么保证一致性
对于数据的写⼊, CPU 都会先写⼊到 Cache ⾥⾯,然后再在找个合适的时机写⼊到内存,那就有「写直达」和「写回」这两种策略来保证 Cache 与内存的数据⼀致性:
- 写直达,只要有数据写⼊,都会直接把数据写⼊到内存⾥⾯,这种⽅式简单直观,但是性能就会受限于内存的访问速度。
- 写回,对于已经缓存在 Cache 的数据的写⼊,只需要更新其数据就可以,不⽤写⼊到内存,只有在需要把缓存⾥⾯的脏数据交换出去的时候,才把数据同步到内存⾥,这种⽅式在缓存命中率⾼的情况,性能会更好;
多核怎么保证缓存一致性
每个核⼼都有各⾃独⽴的 L1/L2 Cache,只有 L3 Cache 是多个核⼼之间共享的。同步不同核心的缓存数据,要做到以下两点:
①写传播(Wreite Propagation):某个 CPU 核⼼⾥的 Cache 数据更新时,必须要传播到其他核⼼的 Cache。
②事务的串形化(Transaction Serialization) :某个 CPU 核⼼⾥对数据的操作顺序,必须在其他核⼼看起来顺序是⼀样的。要实现事务串形化,要做到 2 点:
- CPU 核⼼对于 Cache 中数据的操作,需要同步给其他 CPU 核⼼;
- 要引⼊「锁」的概念,如果两个 CPU 核⼼⾥有相同数据的Cache,那么对于这个 Cache 数据的更新,只有拿到了「锁」,才能进⾏对应的数据更新
基于总线嗅探机制的 MESI 协议,满足了以上两点。整个 MESI 状态的变更,则是根据来自本地 CPU 核⼼的请求,或者来自其他 CPU 核心通过总线传输过来的请求,从而构成⼀个流动的状态机。另外,对于在「已修改」或者「独占」状态的 Cache Line,修改更新其数据不需要发送广播给其他 CPU 核心。
2 CPU如何执行任务
Cache Line
CPU 读写数据的时候,并不是按⼀个⼀个字节为单位来进⾏读写,⽽是以 Cache Line(缓存行) ⼤⼩为单位, Cache Line ⼤⼩⼀般是 64 个字节,CPU 读写数据的时候,每⼀次都是以 64 字节⼤⼩为⼀块进⾏操作。
Cache伪共享
如果我们操作的数据是数组,那么访问数组元素的时候,按内存分布的地址顺序进⾏访问,这样能
充分利⽤到 Cache,程序的性能得到提升。但如果操作的数据不是数组,⽽是普通的变量,并在多核 CPU的情况下,我们还需要避免 Cache Line 伪共享的问题。
Cache Line 伪共享问题就是,多个线程同时读写同⼀个 Cache Line 的不同变量时,⽽导致 CPU
Cache 失效的现象。那么对于多个线程共享的热点数据,即经常会修改的数据,应该避免这些数据刚好在同⼀个 Cache Line 中,避免的⽅式⼀般有 Cache Line ⼤⼩字节对⻬,以及字节填充等⽅法。
如何选择线程
系统中需要运⾏的多线程数⼀般都会⼤于 CPU 核⼼,这样就会导致线程排队等待 CPU,这可能会产⽣⼀定的延时,如果我们的任务对延时容忍度很低,则可以通过⼀些⼈为⼿段⼲预 Linux 的默认调度策略和优先级。
调度类-保证高优先级的任务尽早的被执行
Linux中,任务优先级数值越小,其优先级越高。
实时任务:0-99
普通任务:100-139
有三种调度类:Deadline和Realtime用于实时任务,Fair用于普通任务。
CFS调度器(完全公平调度,Completely Fair Scheduling)
如果我们启动任务的时候,没有特意去指定优先级的话,默认情况下都是普通任务,普通任务的调度类是Fail,由 CFS 调度器来进⾏管理。
在 CFS 算法调度的时候,会优先选择 vruntime 少的任务。
可以通过调整NICE值(优先级的修正数值),让优先级高的任务执行时间更多。
运行队列
每个 CPU 都有⾃⼰的运⾏队列(Run Queue, rq) ,⽤于描述在此 CPU 上所运⾏的所有进程。
这⼏种调度类是有优先级的,优先级如下: Deadline > Realtime > Fair,这意味着 Linux 选择下⼀个任务执⾏的时候,会按照此优先级顺序进⾏选择,也就是说先从 dl_rq ⾥选择任务,然后从 rt_rq ⾥选择任务,最后从 csf_rq ⾥选择任务。因此, 实时任务总是会⽐普通任务优先被执⾏。
3 软中断
中断是什么
中断是系统⽤来响应硬件设备请求的⼀种机制,操作系统收到硬件的中断请求, 会打断正在执⾏的进程,然后调⽤内核中的中断处理程序来响应请求。
中断是⼀种异步的事件处理机制,可以提⾼系统的并发处理能⼒。
中断请求的处理程序应该要短且快,这样才能减少对正常进程运⾏调度地影响,才能避免其他设备的中断请求丢失。
什么是软中断
为了解决中断处理程序执⾏过⻓和中断丢失的问题,将中断过程分成了两个阶段,分别是「上半部和下半部分」 。
上半部直接处理硬件请求,也就是硬中断,主要是负责耗时短的⼯作,特点是快速执行;
下半部是由内核触发,也就说软中断, 主要是负责上半部未完成的⼯作,通常都是耗时⽐较⻓的事情,特点是延迟执行。
硬中断会打断CPU正在执行的任务,立即执行中断处理程序。
软中断是以内核线程的⽅式执⾏,并且每⼀个 CPU 都对应⼀个软中断内核线程。
软中断不只是包括硬件设备中断处理程序的下半部,⼀些内核⾃定义事件也属于软中断,⽐如内核调度等、 RCU 锁(内核⾥常⽤的⼀种锁)等。
软中断是以内核线程的⽅式执⾏的。
4 计算机系统对数字的存储
为什么负数要用补码存储
为了和正数的加减操作一样。
补码 = 反码 + 1;
反码 = 所有数反过来;
如果负数不用补码存储, 还需要多⼀步操作来判断是否为负数,如果为负数,还得把加法反转成减法,或者把减法反转成加法。
十进制小数怎么转换成二进制
整数部分“除2取余法”,小数部分“乘2取余法”
为什么0.1 + 0.2 不等于 0.3
小数部分转换为二进制的方法:每次*2后取出整数部分。例如:
0.625 -> 0.101
0.1 -> 0.0001100110…
由于计算机的资源是有限的,所以是没办法⽤⼆进制精确的表示 0.1,只能⽤「近似值」来表示,会造成精度缺失的情况。
0.1和0.2在计算机中的表达都是近似值,相加也会得到近似值。
计算机用浮点数来存储小数
符号位:表示正数还是负数
指数位:指定小数点的位置,double的指数位更长,可以表示的小数范围更大。
尾数位:小数点右侧的数字,越长表示的更精确