深入并发之线程、进程、纤程、协程、管程

一、进程、线程、纤程、协程、管程概念理解

在现在你可能会经常看到进程、线程、纤程、协程、管程、微线程、绿色线程…一大堆xx程的概念,其实这些本质上都是为了满足并行执行、异步执行而出现的一些概念。

因为随着如今的科技越来越发达,计算机目前多以多核机器为主,所以之前单线程的串行执行方式注定无法100%程度发挥出硬件该有的性能。同时,为了满足互联网时代中日益渐增的用户基数,我们开发的程序往往需要更优异的性能,更快的执行效率,更大的吞吐量才可。

为了方便理解,我们可以先把操作系统抽象为了一个帝国。并且为了方便理解这些概念,下面也不会太过官方死板的做概念介绍。

1.1、进程(Progress)

进程也就是平时所说的程序,比如在操作系统上运行一个谷歌浏览器,那么就代表着谷歌浏览器就是一个进程。进程是操作系统中能够独立运行的个体,并且也作为资源分配的基本单位,由指令、数据、堆栈等结构组成。 安装好一个程序之后,在程序未曾运行之前也仅是一些文件存储在磁盘上,当启动程序时会向操作系统申请一定的资源,如CPU、存储空间和I/O设备等,OS为其分配资源后,会真正的出现在内存中成为一个抽象的概念:进程。

其实操作系统这个帝国之上,在运行时往往有着很多个进程存在,你可以把这些进程理解成一个个的工厂,根据各自的代码实现各司其职。如通过Java编写一个程序后运行在操作系统上,那么就相当于在OS帝国上注册了一家工厂,该工厂具体的工作则由Java代码的业务属性决定。

随着计算机硬件技术的不断进步,慢慢的CPU架构更多都是以多核的身份出现在市面上,所以对于程序而言,CPU利用率的要求会更高。但是进程的调度开销是比较大的,并且在并发中切换过程效率也很低,所以为了更高效的调度和满足日益复杂的程序需求,最终发明了线程。

1.2、线程(Thread)

在操作系统早期的时候其实并没有线程的概念,到了后来为了满足并发处理才推出的一种方案,线程作为程序执行的最小单位,一个进程中可以拥有多条线程,所有线程可以共享进程的内存区域,线程通常在运行时也需要一组寄存器、内存、栈等资源的支撑。现如今,程序之所以可以运行起来的根本原因就是因为内部一条条的线程在不断的执行对应的代码逻辑。

假设进程现在是OS帝国中的一个工厂,那么线程就是工厂中一个个工位上的工人。工厂之所以能够运转的根本原因就在于:内部每个工位上的工人都各司其职的处理自己分配到的工作。

多核CPU中,一个核心往往在同一时刻只能支持一个内核线程的运行,所以如果你的机器为八核CPU,那么理论上代表着同一时刻最多支持八条内核线程同时并发执行。当然,现在也采用了超线程的技术,把一个物理芯片模拟成两个逻辑处理核心,让单个处理器都能使用线程级并行计算,进而兼容多线程操作系统和软件,减少了CPU的闲置时间,提高的CPU的运行效率。比如四核八线程的CPU,在同一时刻也支持最大八条线程并发执行。

在OS中,程序一般不会去直接申请内核线程进行操作,而是去使用内核线程提供的一种名为LWP的轻量级进程(Lightweight Process)进行操作,这个也就是平时所谓的线程,也被成为用户级线程。

1.2.1、线程模型

在如今的操作系统中,用户线程与内核线程主要存在三种模型:一对一模型、多对一模型以及多对多模型。

一对一模型
一对一模型是指一条用户线程对应着内核中的一条线程,而Java中采用的就是这种模型,如下:
在这里插入图片描述

Java线程一对一模型 一对一模型是真正意义上的并行执行,因为这种模型下,创建一条Java的Thread线程是真正的在内核中创建并映射了一条内核线程的,执行过程中,一条线程不会因为另外一条线程的原因而发生阻塞等情况。不过因为是直接映射内核线程的模式,所以数量会存在上限。并且同一个核心中,多条线程的执行需要频繁的发生上下文切换以及内核态与用户态之间的切换,所以如果线程数量过多,切换过于频繁会导致线程执行效率下降。

多对一模型
顾名思义,多对一模型是指多条用户线程映射同一条内核线程的情况,对于用户线程而言,它们的执行都由用户态的代码完成切换。
在这里插入图片描述

线程多对一模型

这种模式优点很明显,一方面可以节省内核态到用户态切换的开销,第二方面线程的数量不会受到内核线程的限制。但是缺点也很明显,因为线程切换的工作是由用户态的代码完成的,所以如果当一条线程发生阻塞时,与该内核线程对应的其他用户线程也会一起陷入阻塞。

多对多模型
多对多模型就可以避免上面一对一和多对一模型带来的弊端,也就是多条用户线程映射多条内核线程,这样即可以避免一对一模型的切换效率问题和数量限制问题,也可以避免多对一的阻塞问题,如下:

线程多对多模型
在这里插入图片描述

1.3、协程(Coroutines)

协程是一种基于线程之上,但又比线程更加轻量级的存在,这种由程序管理的轻量级线程也被称为用户空间线程,对于内核而言是不可见的。正如同进程中存在多条线程一样,线程中也可以存在多个协程。

协程在运行时也有自己的寄存器、上下文和栈,协程的调度完全由用户控制,协程调度切换时,会将寄存器上下文和栈保存到分配的私有内存区域中,在切回来的时候,恢复先前保存的寄存器上下文和栈,直接操作栈则基本没有内核切换的开销,可以不加锁的访问全局变量,所以上下文的切换非常快。

前面把线程比作了工厂工位上的固定工人,那么协程更多的就可以理解为:工厂中固定工位上的不固定工人。一个固定工位上允许有多个不同的工人,当轮到某个工人工作时,就把上一个工人的换下来,把这个要工作的工人换上去。或者当前工人在工作时要上厕所,那么就会先把当前工作的工人撤下去,换另一个工人上来,等这个工人上完厕所回来了,会再恢复它的工作。 协程有些类似于线程的多对一模型。

1.4、纤程(Fiber)

纤程(Fiber)是Microsoft组织为了帮助企业程序的更好移植到Windows系统,而在操做系统中增加的一个概念,由操作系统内核根据对应的调度算法进行控制,也是一种轻量级的线程。

纤程和协程的概念一致,都是线程的多对一模型,但有些地方会区分开来,但从协程的本质概念上来谈:纤程、绿色线程、微线程这些概念都属于协程的范围。纤程和协程的区别在于:

纤程是OS级别的实现,而协程是语言级别的实现,纤程被OS内核控制,协程对于内核而言不可见。

1.5、管程(Monitors)

管程(Monitors)提供了一种机制,线程可以临时放弃互斥访问,等待某些条件得到满足后,重新获得执行权恢复它的互斥访问。

1.6、XX程小结

先如今各种程出现的根本原因是由于多核机器的流行,所以程序实现中也需要最大程度上考虑并行、并发、异步执行,在最大程序上去将硬件机器应有的性能发挥出来。以Java而言,本身多线程的方式是已经可以满足这些需求的,但Java中的线程资源比较昂贵,是直接与内核线程映射的,所以在上下文切换、内核态和用户态转换上都需要浪费很多的资源开销,同时也受到操作系统的限制,允许一个Java程序中创建的纤程数量是有限的。所以对于这种一对一的线程模型有些无法满足需求了,最终才出现了各种程的概念。

从实现级别上来看:进程、线程、纤程是OS级别的实现,而绿色线程、协程这些则是语言级别上的实现。 从调度方式上而言:进程、线程、绿色线程属于抢占式执行,而纤程、协程则属于合作式调度。 从包含关系上来说:一个OS中可以有多个进程,一个进程中可以有多条线程,而一条线程中则可以有多个协程、纤程、微线程等。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值