1. 平均负载
平均负载是指单位时间内,系统处于可运行状态和不可中断状态的平均进程数,也就是平均活跃进程数,它和CPU使用率并没有直接关系。
可运行状态的进程是指正在使用CPU或者等待CPU资源的进程。当我们使用类似于”ps”命令时,这些进程通常以”R”状态(Running或Runnable)显示。
不可中断状态的进程是指处于内核态关键流程中的进程,这些流程无法被中断。例如,最常见的情况是等待硬件设备的I/O响应。这类进程在”ps”命令中以”D”状态(Uninterruptible Sleep,也称为Disk Sleep)显示。
举个例子,当一个进程正在进行磁盘读写操作时,为了保证数据的一致性,在收到磁盘响应之前,该进程不能被其他进程或中断打断。此时,该进程处于不可中断状态。如果该进程被打断,可能会导致磁盘数据与进程数据不一致的问题。
因此,不可中断状态实际上是系统对进程和硬件设备的一种保护机制。
从理想角度来看,每个CPU都刚好运行一个进程将充分利用每个CPU的资源。例如,当平均负载为3时,对于只有3个CPU的系统而言,表示所有CPU都被完全占用。对于4个CPU的系统而言,意味着CPU有50%的空闲时间。而对于只有1个CPU的系统而言,意味着有一半的进程无法竞争到CPU资源。
所以可总结如下:
-
平均负载高于CPU核心数时,通常意味着系统负载较重。这可能是因为有更多的进程在竞争CPU资源,导致CPU使用率较高。如果平均负载远高于CPU核心数,可能会导致进程排队等待CPU,造成性能下降。
-
平均负载低于或接近CPU核心数时,通常表示系统负载较轻。这意味着CPU使用率相对较低,系统有足够的处理能力来处理当前的工作负载。
2. 平均负载与CPU使用率之间关系
先说一个小栗子,假设一个系统有4个CPU核心,如果平均负载是2,表示平均活跃进程数为2。这并不直接告诉我们每个CPU核心的使用率是多少。可能有两个CPU核心各自运行一个进程,而其他两个CPU核心处于空闲状态;也可能有一个CPU核心运行两个进程,而其他三个CPU核心处于空闲状态。因此,平均负载为2时,并不能确定具体的CPU使用率。
总结起来:
-
CPU密集型进程:当系统中有大量的CPU密集型进程正在执行,它们会消耗大量的CPU资源,导致CPU使用率升高。同时,这些进程也会占用系统的可运行状态,使得平均负载也升高。在这种情况下,CPU使用率和平均负载是一致的,都反映了系统的高负载状态。
-
I/O密集型进程:如果系统中有大量的I/O密集型进程,它们可能会频繁地进行I/O操作并等待I/O响应。在等待I/O的过程中,进程不会占用CPU资源,因此CPU使用率可能相对较低。然而,这些等待I/O的进程会进入不可中断状态,导致平均负载升高。因此,在这种情况下,平均负载可能比CPU使用率更高。
-
大量等待CPU的进程调度:当系统中存在大量的进程在等待CPU调度时,它们可能会竞争有限的CPU资源。这会导致CPU使用率的升高,因为CPU正在不断地被分配给各个进程。同时,这些等待CPU调度的进程会占用系统的可运行状态,使得平均负载升高。因此,在这种情况下,CPU使用率和平均负载可能都比较高。
3. CPU上下文切换
CPU上下文切换是指操作系统在多任务环境下,将当前正在运行的进程或线程的上下文信息保存起来,并加载下一个即将运行的进程或线程的上下文信息的过程。
上下文是指进程或线程在执行过程中的状态信息,包括程序计数器(记录下一条要执行的指令地址)、寄存器的值、堆栈指针、打开的文件、内存映射等。上下文切换的目的是在多个进程或线程之间共享CPU时间,使得每个进程或线程都能得到适当的执行时间。
当一个进程或线程的时间片(时间片是操作系统分配给每个进程或线程的执行时间段)用完或发生某种事件(如I/O操作完成)时,操作系统会进行上下文切换,具体过程如下:
-
保存当前进程或线程的上下文信息:操作系统会将当前进程或线程的上下文信息保存到内存中,包括寄存器的值、程序计数器等。
-
加载下一个进程或线程的上下文信息:操作系统从就绪队列中选择下一个即将执行的进程或线程,并将其上下文信息从内存中加载到寄存器和其他相关硬件中。
-
切换到下一个进程或线程的执行:操作系统将控制权转移到下一个进程或线程,使其开始执行。这个过程可能包括更新页表、设置内存映射、打开文件等操作。
上下文切换是一个开销较大的操作,因为它涉及到大量的数据保存和加载操作。因此,减少上下文切换的次数对系统性能至关重要。一些常见的导致上下文切换的情况包括抢占式调度、I/O操作、中断处理和多核处理器上的并发执行等。
3-1 进程上下文切换
进程上下文切换是操作系统在多任务环境下,从一个进程切换到另一个进程时所进行的上下文切换过程。它涉及保存和加载进程的上下文信息,以便在重新调度时能够继续执行进程。
进程上下文切换的过程如下:
-
保存当前进程的上下文:当操作系统需要切换到另一个进程时,它会先保存当前正在运行进程的上下文信息。这包括保存进程的程序计数器、寄存器的值、堆栈指针、打开的文件、内存映射等。这些信息通常保存在进程的控制块(Process Control Block,PCB)中,PCB是操作系统用来管理进程的数据结构。
-
加载下一个进程的上下文:操作系统从就绪队列中选择下一个即将执行的进程,并加载该进程之前保存的上下文信息。这包括将进程的程序计数器、寄存器的值、堆栈指针等从其PCB中加载到相应的寄存器和硬件中。
-
切换到下一个进程的执行:一旦新进程的上下文信息加载完毕,操作系统会将控制权转移到该进程,使其开始执行。这可能涉及更新页表、设置内存映射、打开文件等操作,以确保新进程能够正确地运行。
进程上下文切换是一个开销较大的操作,因为它涉及大量的数据保存和加载。上下文切换的频繁发生会导致系统性能下降。因此,优化上下文切换的效率对于提高系统的多任务处理能力至关重要。
进程上下文切换通常发生在以下情况下:
-
抢占式调度:当操作系统采用抢占式调度策略时,一个优先级更高的进程可能会抢占正在执行的进程的CPU时间,从而导致上下文切换。
-
I/O操作:当进程需要进行I/O操作时,例如等待磁盘读写完成,操作系统会将该进程切换出去,让其他进程继续执行。一旦I/O操作完成,操作系统会将该进程的上下文切换回来,使其继续执行。
-
时间片用完:操作系统为每个进程分配一定的时间片,当一个进程的时间片用完时,操作系统会将其上下文保存并切换到下一个进程,以保证公平分配CPU时间。
-
进程间通信:在进程间通信的过程中,操作系统可能需要进行上下文切换,以便让不同的进程能够相互交互和共享数据。
- 进程在系统资源不足(比如内存不足)时,要等到资源满足后才可以运行,这个时候进程也会被挂起,并由系统调度其他进程运行。
- 当进程通过睡眠函数 sleep 这样的方法将自己主动挂起时,自然也会重新调度。
3-2 线程上下文切换
线程和进程最大的区别在于,线程是调度的基本单位,而进程是资源拥有的基本单位。在内核中的任务调度过程中,调度对象实际上是线程,而进程只是为线程提供了虚拟内存、全局变量等资源。因此,可以将线程视为进程的子任务。
当进程包含多个线程时,这些线程共享相同的虚拟内存和全局变量等资源。在上下文切换时,这些资源是不需要被修改的。
然而,线程也有自己的私有数据,例如栈和寄存器等。在上下文切换时,需要保存和加载线程的私有数据。
因此,线程的上下文切换可以分为两种情况:
-
前后两个线程属于不同的进程:在这种情况下,由于资源不共享,线程的上下文切换过程与进程的上下文切换相似。
-
前后两个线程属于同一个进程:在这种情况下,由于虚拟内存是共享的,上下文切换时虚拟内存等资源保持不变,只需要切换线程的私有数据和寄存器等非共享数据。
可以看出,同一个进程内的线程切换相比多进程间的切换消耗更少的资源。这也是使用多线程代替多进程的一个优势。
3-3 中断上下文切换
中断上下文切换是指当计算机系统发生硬件中断或异常时,操作系统需要从当前正在执行的上下文中切换到中断处理程序的上下文,并在中断处理程序执行完毕后再切换回原来的上下文。中断上下文切换是操作系统为了响应中断事件而进行的一种上下文切换过程。
下面是中断上下文切换的详细过程:
-
中断触发:计算机系统中的硬件设备(如时钟、键盘、磁盘等)或异常条件(如除零错误、页错误等)触发了中断信号,通知操作系统需要进行相应的处理。这会导致当前正在执行的指令被暂停。
-
保存当前上下文:在响应中断前,操作系统会保存当前正在执行的任务的上下文信息。这包括保存程序计数器、寄存器的值、堆栈指针等。这些信息通常保存在被中断任务的内核栈或专用的中断栈中。
-
切换到中断处理程序:一旦当前上下文保存完毕,操作系统会切换到中断处理程序的上下文。中断处理程序是预先定义好的用于处理特定中断的代码段。操作系统会根据中断类型和优先级选择相应的中断处理程序。
-
中断处理程序执行:操作系统开始执行中断处理程序,处理中断事件。中断处理程序根据中断类型进行相应的处理,可能包括读取输入设备的数据、处理异常错误、更新系统状态等。
-
恢复原上下文:一旦中断处理程序执行完毕,操作系统会从中断处理程序的上下文中恢复原来被中断任务的上下文。它会将之前保存的程序计数器、寄存器的值、堆栈指针等信息恢复到相应的寄存器和硬件中。
-
继续执行被中断任务:一旦原上下文恢复完毕,操作系统会继续执行被中断的任务。它会从中断发生时的位置继续执行指令,使任务在中断处理后继续正常运行。
-
与进程上下文切换不同,中断上下文切换并不牵涉到进程的用户态(User Mode)。当发生中断时,即使当前正在执行的进程处于用户态,操作系统也不需要保存和恢复该进程的虚拟内存、全局变量等用户态资源。
中断上下文只包括内核态(Kernel Mode)中断服务程序执行所必需的状态。这些状态包括CPU寄存器的值、内核堆栈的指针、硬件中断参数等。这些信息足够操作系统在中断处理程序中进行必要的操作,而不需要涉及进程的用户态资源。
换句话说,中断上下文切换仅涉及到内核态的数据和状态,因为中断处理程序运行在内核态中。它是为了响应硬件中断而发生的,目的是尽快处理中断事件并返回到被中断的任务。
这种区分是为了提高中断响应的效率。通过仅保存和恢复与中断处理相关的内核态数据,可以减少上下文切换的开销,从而更快地响应中断并恢复正常的执行。
中断上下文切换的过程需要保存和恢复大量的上下文信息,因此会引入一定的开销。优化中断上下文切换的方式是减少保存和恢复的上下文信息量,以提高系统的响应速度。