操作系统线程
典型问题:
简述进程和线程的区别
以下内容带您一步步了解
线程是什么
比进程更小的独立运行的基本单位-线程(Threads)
线程的提出主要是为了提高系统内程序并发执行的程度,从而进一步提升系统的吞吐量,充分发挥多核CPU的优越性而设计的
引入进程是为了操作系统更加方便地管理程序,使得多个程序能并发管理和执行
而线程则是为了减少程序在并发执行时的开销,并且提高程序内程序并发执行的程度
从从属关系来看,一个进程对应多个线程,线程是从属于某一进程的
线程的一大特点
轻装上阵
在一些地方称其为轻量级进程
不管在调度,切换,运行都比进程更加轻量
线程是操作系统进行运行调度的最小单位
包含在进程之中,是进程中实际运行工作的单位
一个进程可以并发多个线程,每个线程执行不同的任务
线程强调的是运行
进程强调的是资源分配、
进程与线程的关系
进程的线程共享进程资源
因为操作系统在进行资源分配时并不是以线程为单位的,而是以进程为单位
线程本身是不拥有资源的
用户态/内核态
典型问题:
简述操作系统的内核态
简述进程什么时候进入内核态
以下内容带您一步步了解
操作系统资源管理
有处理器资源,IO设备资源,存储器资源,文件资源等等
这些资源都是交给操作系统去直接管理的,用户是不能直接接触到的,都是通过操作系统提供的接口来处理的
为了屏蔽用户可能对计算机所造成的影响,操作系统就把操作系统的状态分为内核态和用户态2个部分
关键的程序就运行在内核态
用户所编写的程序在没有必要的情况下一般都是运行在用户态
以Linux作为例子
Linux设计的哲学
对不同的操作赋予不同的执行等级
与系统相关的一些特别关键的操作必须由最高特权的程序来完成
内核态
内核是操作系统的内部核心程序,它向外部提供了对计算机设备的核心管理调用
我们将操作系统的代码分成2部分
内核所在的地址空间称作内核空间
内核空间:存放的是内核代码和数据
内核态一般指的是运行在内核空间的程序和代码的状态
当执行到内核空间的一段代码时,我们称程序处于内核态
内核态下的程序可以访问所有资源和设备
用户态
在内核以外的统称为外部管理程序,它们大部分是对外围设备的管理和界面操作
外部管理程序与用户进程所占据的地址空间称为用户(外部)空间
当程序执行到外部空间代码时,我们称程序处于用户态
在此状态下,执行的代码被硬件限定,不能进行某些操作,以防止给操作系统带来安全隐患
内核态/用户态切换
从用户态切换到内核态主要有3种情况:
系统调用
操作系统管理资源时为我们提供了很多接口,通过这些接口就可以操作这些资源
这些接口就可以理解为系统调用
所有用户程序都是运行在用户态,但是有时候这些用户态的程序也需要做一些内核态的事情
比如说从硬盘读取数据,从网卡里读写数据,这些都只能由操作系统来完成
这时就要通过系统调用的操作来把这些工作交给操作系统去执行
进行了系统调用后,当前用户程序就会由用户态切换到内核态去执行
当系统调用完成后,会返回数据,用户态程序拿到数据后,它又返回到用户态来继续执行
异常中断
如CPU在执行用户态程序时突然发生了一些不可预知的事件如内存不存在,当前访问程序出现异常等
异常只能由操作系统去管理,这时进程就会由用户态切换到内核态,让操作系统去处理相关异常事件
外围设备中断
在读写外围设备时,如果说外围设备在完成工作之后,它可以给CPU发出中断信号,可以暂停当前需要执行的指令,转而去执行中断信号对应的处理程序
如暂停当前需要执行的指令的程序是用户态的程序的话,那么它处理外围设备中断时就会转为内核态去执行
著名事件Intel meltdown漏洞
就是由于通过漏洞跳过以上3种步骤进行了切换,越权,使得用户程序也可以拥有最高的执行权限
程序运行类型分析
典型问题:
举例说明什么是IO密集型任务
IO密集型任务部署时,应该注意什么
以下内容带您一步步了解
计算密集型
也称为CPU密集型
完成一项任务的时间取决于CPU的速度
特点:
CPU利用率高,并且运行时很可能导致别的程序处理慢的情况
对处理器资源(高频使用)要求很高,对于其它资源(低频使用)要求较低
计算1024000的阶乘就是典型的计算密集型的任务
IO密集型
完成一项任务的时间取决于IO设备的速度
特点:
频繁读写网络、磁盘等任务都属于IO密集型任务
即磁盘的读取数据和输出数据非常大的时候就属于IO密集型
CPU利用率低,大部分时间在等待设备完成
这是由于IO操作的运行时间远远大于CPU、内存运行时间,所以任务的大部分时间都是在等待IO操作完成
对存储器资源(高频使用)要求很高,对于其它资源(低频使用)要求较低
往磁盘写入10G的文件就是个典型的IO密集型
结合进程,线程来理解
计算密集型
计算密集型通过多线程的改造带来了很大的效率提升
如计算1024000的阶乘,有个多核CPU
如果是单进程单线程去运行还有其它核没有利用到
这就要通过多线程才能充分利用CPU资源
通过合理的设计把任务拆分给多个线程来提升效率
IO密集型
IO密集型通过多线程的改造带来不了很大的效率提升
如往磁盘里写入10G的文件
大部分时间都是在等待,都是在等存储器把数据写完成的
在等待时间里,程序是处于阻塞的状态
在阻塞状态程序并没有使用CPU而是被挂起了
所以在这种情况下对程序进行多线程改造也不能很好地提升运行效率
程序运行类型分析
游戏画面渲染涉及很多数学操作,是典型的计算密集型任务
复制粘贴本质上是对文件内容的复制,所以它是典型的IO密集型任务
图片卷积处理是典型的计算密集型任务
下载工具涉及到网络IO和磁盘IO,是典型的IO密集型任务
AI模型训练既属于计算密集型,也属于IO密集型,即混合密集型
视频解码既要读,也要解码,既属于计算密集型,也属于IO密集型,即混合密集型
协程基础
典型问题:
协程是什么?为什么需要协程
多协程可以发挥多核CPU的优势吗?为什么?
以下内容带您一步步了解
上下文切换
主要存在于分时系统里
Linux是一个多任务操作系统,它支持远大于CPU数量的任务同时运行(主要得益于多道程序设计)
当然,这些任务实际上并不是真的在同时运行,而是因为系统在很短的时间内,将CPU轮流分配给它们,造成多任务同时运行的错觉
而在每个任务运行前,CPU都需要知道任务从哪里加载,又从哪里开始运行(上下文数据)
有寄存器级上下文,用户级上下文,系统级上下文等等
上下文切换过程
1.准备就绪进程运行数据
2.保存当前进程运行状态
3.迁出当前进程数据
4.迁入就绪进程数据
5.恢复就绪进程上一次运行状态
6.就绪进程开始运行
切换会涉及到用户态和内核态的切换,它是通过系统调用来完成这个切换的
每一次切换都需要一定时间,每秒钟切换次数还很高,是需要一定时间成本的
协程
在很多资料上也叫微线程,纤程以及协作式线程
特点:
比线程更小的粒度
运行效率更高
可以支持更高的并发
正如一个进程可以拥有多个线程一样,一个线程也可以拥有多个协程
协程的本质是用户级线程
线程更多指的是内核级线程,内核级线程是由操作系统内核提供的
而协程(用户级线程)它是由用户态的程序提供的
协程不是被操作系统内核所管理,而完全是由程序所控制(也就是在用户态执行)
协程为什么叫协作式线程?
用户态的多个协程可以对应1个线程
还因为协程本身只运行在用户态,并且它是由用户自行调度的,内核无法干涉
协作运行,相互让步
正常的程序逻辑是从上往下顺序执行的
如果有协程的加入的话,就可以把这个逻辑拆为2个部分
2者是相互让步的,它们并没有产生抢夺式的调度,而是主动让出CPU
所以说它们是一个协作的关系
协程的优缺点
调度,切换,管理更加轻量
不管是调度,切换,管理都并没有在内核态产生任何的操作
比如调度是通过相互让步产生的,管理也是在用户态实现的
内核无法感知协程的存在
因为协程和线程之间是多对一的关系
内核只能感知到线程,因为线程的数据结构是维护在内核的
但是因为协程是在用户态,内核无法感知
所以说协程调度出了什么问题的话,内核也没有办法去干预
设计体现
可以减少上下文切换的成本
内核无法感知到协程存在,CPU内核只能感知到线程,只能对线程进行调度,因此协程是无法发挥CPU的多核优势
主要运用在多IO的场景(比如说高并发的用户接入)