线程
线程是用来运行进程中的指令的,也就是真正执行运算的。数据存放在进程中,线程会去取数据然后利用ALU,寄存器这些计算存储单元去运行进程中的指令。线程有自己的ALU,指令地址寄存器和缓存,上面提到过核和CPU是挨在一起的。
线程上下文切换
接下来把线程可以理解成就是核
如果某个指令比较耗时,那么程序就会卡住
比如指令1和2是IO,指令三四是简单的计算。通过拆分线程1执行指令一二,线程2去做指令三四可以大大提高程序执行效率
所以我们需要有多个线程去运行,因此线程是瓜分进程内存指令运行的,这个线程运行一会,那个线程运行一会。所谓内核中的任务调度,实际上的调度对象是线程;而进程只是给线程提供了虚拟内存、全局变量等资源。
线程也有自己的私有数据,比如栈和寄存器,当前运行到哪个地方了等,这些在上下文切换时也是需要保存的。线程的上下文切换其实就可以分为两种情况:
两个线程属于不同进程,因为资源不共享,切换过程和切换进程上下文一样
两个线程属于同一个进程,只需要切换线程的私有数据、寄存器等不共享的数据,内存地址等还是共享的同一个进程的。
流程
假设Core1运行线程1,Core2运行线程2;线程1运行指令1,2;线程2运行指令3,4~~~
~线程1运行完指令1的时候内核发生调度当前运行这个线程的核Core1保存线程1的运行位置寄存器栈等数据;然后线程2执行完指令3的时候同样也是将数据保存到Core2中。 此时切换到Core1执行的时候保存当前执行的Core2数据,恢复取出Core1上次保存的信息也就是执行指令2,执行线程2的时候也是一样的,保存Core1信息,恢复Core2执行指令4。
可以看到和进程的上下文切换对比,线程切换更轻量,保存的上下文信息更少,也不需要保存到TCB内存区域中。(量少速度快)
线程是一个独立可执行单元,也就是CPU内部的核,我们总说四核处理器八核处理器,意思就是一个CPU内部可以运行多少个线程,一个核运行一个线程,上面也说过核就是一个独立可执行单元,他有自己的计算单元ALU,缓存还有指令地址寄存器等等。
单核双线程技术:一般来说一个核是一个线程,但是现在可以做到一个核可以运行两个线程,他的本质大家可以猜想下:核的内部有两个线程运行,和CPU运行多个核的道理一样。也是核内部运行这个线程一会,运行那个线程一会,有单独的空间去存储线程运行到哪个地方了。
线程越多越好吗?
此处分析的是单CPU多核的情况,如果是多CPU架构的可以做到真正的并行运行多个线程会比单CPU只是切换调度实现并发的更好。
并不是,线程的运行看起来是并行的,但是底层其实是CPU在分配时间片让每个进程(其实真正做运算的是线程只不过是从宏观上考虑多个进程也即多个线程)都可以得到执行(默认主线程)。当切换的时候需要保存好当前线程的上下文信息,再进行切换。如果线程过多比如几万个即使每次切换现场都是很快也会有很大的时间浪费在保存上下文上;
除此之外如果是不同进程的线程,每次切换都需要将进程的所有数据保存到PCB中,耗时比同一个进程的线程切换更严重。
总结
最后总结下之前的关于硬件层面CPU的发展:
- 指令运行速度快了,但是依赖的数据却需要很长时间才能获取到,因此我们在CPU内部设立了缓存,因为缓存存在一致性问题,因此又有了脏位
- 每次执行指令都需要经过固定的三个步骤取指令,解码,执行,这三个步骤执行完成就完成了一条指令的执行,但是这三个步骤其实是可以串起来的,因此我们缩短到一个时钟周期就可以完成一个指令
- 如果当前指令的执行阶段和下一个指令的解码阶段是有依赖的那么就会发生错误,因此计算机需要识别指令依赖问题;然后我们又对分支预测做了优化
- 但是还是太慢,执行阶段其实有些部分还是空闲的,因此对于某些依赖不同部件的执行指令可以同时运行,并且多加几个相同电路让频繁执行的指令减少浪费时间在等待上;
- 当某些指令比较耗时的话会影响其他指令的运行CPU出了乱序执行优化指令顺序;
- 上面的优化都是在对一条指令执行速度的优化,如果我们可以同时运行多个指令呢? 一个核是一个独立的执行单元也即每次只能运行一条指令(我们之前的优化就是对一个核运行的更快速高效)。
- 多核处理器,每次可以并发运行多个指令(同一时间还是只有一个线程运行,切换核的速度特别快可以几乎不计)让程序的执行更加高效
- 现在都是多个CPU多核了,可以真正实现并行运行程序(同一时间多个程序同时运行)
我正在参与2023腾讯技术创作特训营第二期有奖征文,瓜分万元奖池和键盘手表