由于CPU是串行的,因此对于单核CPU来说,同一时刻一定是只有一个线程在占用CPU资源的。因此,Linux作为一个多任务(进程)系统,会频繁的发生进程/线程切换。
进程是由内核来管理和调度的,进程的切换只能发生在内核态,
用户空间资源:虚拟内存、栈、全局变量
内核资源:堆栈、寄存器等内核空间的状态
就叫做进程上下文。
线程是操作系统调度的最小单位。
同时线程会共享父进程的虚拟内存和全局变量等资源,因此 父进程的资源加上线上自己的私有数据就叫做线程的上下文。
现在就更容易解释了,进程和线程的切换,会产生CPU上下文切换和进程/线程上下文的切换。而这些上下文切换,都是会消耗额外的CPU的资源的。
进一步谈谈协程的上下文切换
那么协程就不需要上下文切换了吗?
需要,但是不会产生 CPU上下文切换和进程/线程上下文的切换,因为这些切换都是在同一个线程中,即用户态中的切换,你甚至可以简单的理解为,协程上下文之间的切换,就是移动了一下你程序里面的指针,CPU资源依旧属于当前线程。
需要深刻理解的,可以再深入看看Go的GMP模型。
最终的效果就是协程进一步压榨了CPU的有效利用率。
CPU,全名Central Processing Unit(中央处理器)。这是一块超大规模的集成电路,包含上亿的晶体管,是一台计算机的运算核心(Core)和控制核心(ControlUnit)。它的功能主要是解释计算机指令以及处理计算机软件中的数据。
它的主要构成是:运算器、控制器、寄存器
CPU的工作核心是从程序或应用程序中获取指令并且执行计算。
这个过程一共有三个关键阶段:提取,解码和执行。
CPU先从系统的RAM中提取指令,随后解码该指令的实际内容,最后再由CPU的相关部分执行该指令。
在每个任务运行前,CPU都需要知道从哪里加载,从哪里运行,这些信息保存在CPU寄存器
和操作系统的程序计数器
里面,这两样东西就叫做 CPU上下文。
寄存器是CPU内部用来存放数据的一些小型存储区域,用来暂时存放参与运算的数据
和运算结果
以及一些CPU运行需要的信息
。
作用:用于存放指令的地址。
程序计数器(Program Counter,PC)用来指出下一条指令在主存储器中的地址。
为了保证程序(在操作系统中理解为进程)能够连续地执行下去,CPU必须具有某些手段来确定下一条指令的地址。
当执行一条指令时,首先需要根据PC中存放的指令地址,将指令由内存取到指令寄存器中
,此过程称,为“取指令”。
与此同时,PC中的地址或自动加1或由转移指针给出下一条指令的地址。此后经过分析指令,执行指令。完成第一条指令的执行,而后根据PC取出第二条指令的地址,如此循环,执行每一条指令。
因此,程序计数器的结构应当是具有寄存信息和计数两种功能的结构。
内核态:也叫内核空间,是内核进程/线程所在的区域。主要负责运行系统、硬件交互。
用户态:也叫用户空间,是用户进程/线程所在的区域。主要用于执行用户程序。
内核态与用户态是操作系统的两种运行级别,当程序运行在3级特权级上时,就可以称之为运行在用户态。因为这是最低特权级,是普通的用户进程运行的特权级,大部分用户直接面对的程序都是运行在用户态;
当程序运行在0级特权级上时,就可以称之为运行在内核态。
运行在用户态下的程序不能直接访问操作系统内核数据结构和程序。当我们在系统中执行一个程序时,大部分时间是运行在用户态下的,在其需要操作系统帮助完成某些它没有权力和能力完成的工作时就会切换到内核态(比如操作硬件)。
为什么要区分内核态和用户态
保护机制。防止用户进程误操作或者是恶意破坏系统。内核态类似于C++的私有成员,只能在类内访问,用户态类似于公有成员,可以随意访问。
这两种状态的主要差别是
处于用户态执行时,进程所能访问的内存空间和对象受到限制,其所处于占有的处理器是可被抢占的
处于内核态执行时,则能访问所有的内存空间和对象,且所占有的处理器是不允许被抢占的。CPU状态之间的转换
用户态—>内核态:唯一途径是通过中断、异常、陷入机制(访管指令)
内核态—>用户态:设置程序状态字PSW
1、系统调用(主动)
这是用户态进程主动要求切换到内核态的一种方式,用户态进程通过系统调用申请使用操作系统提供的服务程序完成工作。比如前例中fork()实际上就是执行了一个创建新进程的系统调用。
由于用户态无法完成某些任务,用户态会请求切换到内核态,内核态通过为用户专门开放的中断完成切换。
而系统调用的机制其核心还是使用了操作系统为用户特别开放的一个中断来实现,例如Linux的int 80h中断。
用户程序通常调用库函数,由库函数再调用系统调用,因此有的库函数会使用户程序进入内核态(只要库函数中某处调用了系统调用),有的则不会。
2、异常(被动)
当CPU在执行运行在用户态下的程序时,发生了某些事先不可知的异常,这时会触发由当前运行进程切换到处理此异常的内核相关程序中,也就转到了内核态,比如缺页异常。
3、外围设备的中断(被动)
当外围设备完成用户请求的操作后,会向CPU发出相应的中断信号,这时CPU会暂停执行下一条即将要执行的指令转而去执行与中断信号对应的处理程序,
如果先前执行的指令是用户态下的程序,那么这个转换的过程自然也就发生了由用户态到内核态的切换。比如硬盘读写操作完成,系统会切换到 硬盘读写的中断处理程序 中执行后续操作等。
page cache即页高速缓存,这是提高虚拟文件系统和磁盘文件系统速度的关键,在绝大多数请下,内核在读写磁盘时都引用了页高速缓存。
Page cache 也叫页缓冲或文件缓冲,是由好几个磁盘块构成,大小通常为4k,在64位系统上为8k,构成的几个磁盘块在物理磁盘上不一定连续,文件的组织单位为一页, 也就是一个page cache大小,文件读取是由外存上不连续的几个磁盘块,到buffer cache,然后组成page cache,然后供给应用程序。
Page cache在linux读写文件时,它用于缓存文件的逻辑内容,从而加快对磁盘上映像和数据的访问。具体说是加速对文件内容的访问,buffer cache缓存文件的具体内容——物理磁盘上的磁盘块,这是加速对磁盘的访问。
Buffer cache 也叫块缓冲,是对物理磁盘上的一个磁盘块进行的缓冲,其大小为通常为1k,磁盘块也是磁盘的组织单位。设立buffer cache的目的是为在程序多次访问同一磁盘块时,减少访问时间。系统将磁盘块首先读入buffer cache **如果cache空间不够时,会通过一定的策略将一些过时或多次未被访问的buffer cache清空。**程序在下一次访问磁盘时首先查看是否在buffer cache找到所需块,命中可减少访问磁盘时间。不命中时需重新读入buffer cache。
对buffer cache 的写分为两种,
Buffer cache 是由物理内存分配,linux系统为提高内存使用率,会将空闲内存全分给buffer cache ,当其他程序需要更多内存时,系统会减少cahce大小。
简单说来,page cache用来缓存文件数据,buffer cache用来缓存磁盘数据。在有文件系统的情况下,对文件操作,那么数据会缓存到page cache,如果直接采用dd等工具对磁盘进行读写,那么数据会缓存到buffer cache。
Buffer(Buffer Cache)以块形式缓冲了块设备的操作,定时或手动的同步到硬盘,它是为了缓冲写操作然后一次性将很多改动写入硬盘,避免频繁写硬盘,提高写入效率。
Cache(Page Cache)以页面形式缓存了文件系统的文件,给需要使用的程序读取,它是为了给读操作提供缓冲,避免频繁读硬盘,提高读取效率。
文件Cache管理是Linux操作系统的一个重要组成部分,尤其是Buffer Cache和Page Cache,在Apache Kafka中也用到了Page Cache。Kafka的消息存储在OS pagecache(页缓存,page cache的大小为一页,通常为4K,在linux读写文件时,它用于缓存文件的逻辑内容,从而加快对磁盘上映像和数据的访问)。
buffer与cache操作的对象就不一样。
1)buffer(缓冲)是为了提高内存和硬盘(或其他I/O设备)之间的数据交换的速度而设计的。
2)cache(缓存)是为了提高cpu和内存之间的数据交换速度而设计的,也就是平常见到的一级缓存、二级缓存、三级缓存。 cpu在执行程序所用的指令和读数据都是针对内存的,也就是从内存中取得的。由于内存读写速度慢,为了提高cpu和内存之间数据交换的速度,在cpu和内存之间增加了cache,它的速度比内存快,但是造价高,又由于在cpu内不能集成太多集成电路,所以一般cache比较小,以后intel等公司为了进一步提高速度,又增加了二级cache,甚至三级cache,它是根据程序的局部性原理而设计的,就是cpu执行的指令和访问的数据往往在集中的某一块,所以把这块内容放入cache后,cpu就不用在访问内存了,这就提高了访问速度。当然若cache中没有cpu所需要的内容,还是要访问内存的。
缓冲(buffers)是根据磁盘的读写设计的,把分散的写操作集中进行,减少磁盘碎片和硬盘的反复寻道,从而提高系统性能。linux有一个守护进程定期清空缓冲内容(即写入磁盘),也可以通过sync命令手动清空缓冲。
Buffer将数据写入到内存里,这个数据的内存空间在Linux系统里一般被称为缓冲区(buffer),写入到内存buffer缓冲区,写缓冲。
Cache从内存读取数据,这个数据的内存空间在Linux系统里一般被称为缓存区(cache),从内存cache读取,缓存区,读缓存。
Cache一般用于读取数据,Buffer一般用于写入数据。内存一般有两个参数Memory Cache和Memory Buffer。Linux 命令 free命令查看的是指的是Memory Cache 不是 CPU Cache.
Linux是尽可能使用内存原则,内存会把剩余的空间申请为cache,而cache不属于free,当系统运行时间很长,我们会发现cache很大,就是这个道理
需要注意的是,当我们看到系统内存使用率很高,free几乎为0时,并不代表系统内存容量有瓶颈!只是系统充分发挥了内存作用。而当有进程需要申请大文件内存时,内核会将部分cache空间回收,回收的内存再分配给进程程序使用。