进程、线程和协程有什么区别

进程

进程就是应用程序的启动实例。比如我们运行一个游戏,打开一个软件,就是开启了一个进程。

进程拥有代码和打开的文件资源、数据资源、独立的内存空间。

有人会认为,要提升CPU的利用率,可以开多个进程,但是开多个进程的话,进程间通讯是个比较麻烦的事情(进程之间地址空间是独立的,需要通过其他方式,例如:管道来解决)

相反,线程之间是可以实现数据共享的,因为线程之间使用的是同一个地址空间。

线程

线程又叫做轻量级进程,是CPU调度的最小单位,线程从属于进程,是程序的实际执行者。

一个进程至少包含一个主线程,也可以有更多的子线程。

多个线程共享所属进程的资源,同时线程也拥有自己的专属资源、拥有自己的栈空间

线程间通信主要通过共享内存,上下文切换很快,资源开销较少,但相比进程不够稳定容易丢失数据

线程和进程一样都是由操作系统的调度器来统一调度,线程本身的数据结构需要占用内存,频繁创建和销毁线程会加大系统的压力。另外,线程太多,系统调度的开销也会增大。

基于上面的情况,提出了线程池解决方案,在初始化的时候批量创建线程,然后用户后续通过队列等方式提交业务逻辑,线程池中的线程进行逻辑的消费工作,这样就可以在操作的过程中降低线程创建和销毁的开销,但是调度的开销还是存在的。

有人给出了很好的归纳:

对操作系统来说,线程是最小的执行单元,进程是最小的资源管理单元。

在多核场景下,如果是I/O密集型场景,就算开多个线程来处理,也未必能提升CPU的利用率,反而会增加线程切换的开销。另外,多线程之间假如存在临界区或者共享数据,那么同步的开销也是不可忽视的。

协程,正好可以解决上面的相关问题。

这个时候我们的主角 协程 就要登场了。

协程,英文Coroutines,是一种比线程更加轻量级的存在。正如一个进程可以拥有多个线程一样,一个线程也可以拥有多个协程

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

协程与线程主要区别是它将不再被内核调度,而是交给了程序自己,而线程是将自己交给内核调度,所以也不难理解golang中调度器的存在。
在这里插入图片描述

协程

定义:协程是轻量级线程。

在一个用户线程上可以跑多个协程,这样就提高了单核的利用率。协程不像进程或者线程,可以让系统负责相关的调度工作,协程是处于一个线程中,系统是无感知的,所以需要在该线程中阻塞某个协程的话,就需要手工进行调度。

协程是一种用户态的轻量级线程,协程的调度完全由用户控制。

一个线程可以拥有多个协程,协程不是被操作系统内核所管理,而完全是由程序所控制。与其让操作系统调度,不如我自己来,这就是协程

在这里插入图片描述
要在用户线程上实现协程是一件很难受的事情,原理类似于调度器根据条件的改变不停地调用各个协程的callback机制,但是前提是大家都在一个用户线程下。要注意,一旦有一个协程阻塞,其他协程也都不能运行了。因此要处理好协程。

最重要的是,协程不是被操作系统内核所管理,而完全是由程序所控制(也就是在用户态执行)。

这样带来的好处就是性能得到了很大的提升,不会像线程切换那样消耗资源。

在这里插入图片描述
这段代码十分简单,即使没用过python的小伙伴应该也能基本看懂。

代码中创建了一个叫做consumer的协程,并且在主线程中生产数据,协程中消费数据。

其中yield 是python当中的语法。当协程执行到yield关键字时,会暂停在那一行,等到主线程调用send方法发送了数据,协程才会接到数据继续执行。

但是,yield让协程暂停,和线程的阻塞是有本质区别的。协程的暂停完全由程序控制,线程的阻塞状态是由操作系统内核来进行切换。

因此,协程的开销远远小于线程的开销

协程的应用

有哪些编程语言应用到了协程呢?我们举几个栗子:

Lua语言

Lua从5.0版本开始使用协程,通过扩展库coroutine来实现。

Python语言

正如刚才所写的代码示例,python可以通过 yield/send 的方式实现协程。在python 3.5以后, async/await 成为了更好的替代方案。

Go语言

Go语言对协程的实现非常强大而简洁,可以轻松创建成百上千个协程并发执行。

Java语言

如上文所说,Java语言并没有对协程的原生支持,但是某些开源框架模拟出了协程的功能,有兴趣的小伙伴可以看一看Kilim框架的源码:

总结:

多进程的出现是为了提升CPU的利用率,特别是I/O密集型运算,不管是多核还是单核,开多个进程必然能有效提升CPU的利用率。而多线程则可以共享同一进程地址空间上的资源,为了降低线程创建和销毁的开销,又出现了线程池的概念,最后,为了提升用户线程的最大利用效率,又提出了协程的概念。

通信方式:
在这里插入图片描述
线程的生命周期
创建:线程从创建到被cpu执行之前的这个阶段。
就绪:指线程已具备各种执行条件,一旦获取cpu便可执行。
运行:表示线程正获得cpu在运行。
阻塞:指线程在执行中因某件事而受阻,处于暂停执行的状态,阻塞的线程不会去竞争cpu。
终止:线程执行完毕,接下来会释放线程占用的资源。

在这里插入图片描述
进程调度算法
在这里插入图片描述

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值