汉无为 / 待分类 / 名相近性相远:进程、线程、协程

0 0

   

名相近性相远:进程、线程、协程

2019-12-02  汉无为

前言

好的架构不是设计出来的,而是修改出来的。同样道理,好的内容不是写完之后束之高阁,而是需要不断地修订。所以,本专栏的内容会不断地修订,追求观点新颖,力图简单但不肤浅。诚然,由于个人的能力总有不全之处,我也欢迎更多的人提出建议并给以指正。

正文

进程、线程和协程这三类事物,虽然都挂着一个“程”,但是名相近性相远。进程和线程是一类,而协程却是另外一类,它跟函数是一家。本文主要是讲述进程、线程、函数和协程之前的区别和联系,有助于各位读者朋友打破思维定势,做到融会贯通。

1、进程和线程

我们目之所见得到的是“代码”这个东西,其实是从静态的角度来看待的事物的。代码跑起来,则变成进程和线程,并且有了生命周期,这是从动态的角度看待事物的。我先从进程入手,然后延伸到线程。请看下面的代码:

执行如下命令:

下面我进行命令的解读:

(1)javac HelloWorld.java,编译java代码,此处与本文主题无关,跳过即可。

(2)java HelloWorld,java命令表示启动了一个进程,这个进程是jvm进程。进程是资源的分配单位,此时CPU分配了各种资源给HelloWorld程序,然后CPU启动main线程。此时,我们可能听着音乐,看着小视频,CPU卖力地在音乐(线程)、视频(线程)和HelloWorld的main线程这三者之间不断地调度和上下文的切换。

需要注意的是:当HelloWorld的main线程执行结束,jvm进程也就结束了。

2、进程和线程小结

进程是资源的分配单位,而线程是运行调度单位。提到线程,往往与CPU时间片的切换密切相关。CPU调度放在线程的背景下去理解,往往简单直白。但是,一旦牵扯到协程,很多人就会迷惑不解,而下文讲的协程则与时间片的切换就没有什么关系了,协程纯粹就是函数级别的“编码技巧”而已。

3、协程:函数的让路

说完了进程和线程,下面该说一下协程了。虽然都挂着一个“程”,但是名相近性相远。进程和线程是一类,而协程却是另外一类,它跟函数是一类。所以,在说协程之前,我先从函数说起。

我们知道,函数定义之后就可以调用,在执行过程中,一气呵成,中间是不会“让路”的,函数没有执行完毕之前,是不会硬生生给其他函数“让路“的。说到“让路”问题,有人会想到生产者和消费者场景,生成者和消费者函数交替执行,相互“让路”。

对于生成货物者和消费者问题来说,那是因为存在两个线程,所以仓库货物不足的时候,消费者线程就暂停了,CPU回头就去执行生产者线程,等仓库堆上产品,消费者线程继续执行。所以:消费者线程->仓库货物不足->生成者线程->消费者线程继续执行,这个过程中消费者线程没有“让路”,而是CPU的调度到了生成者线程。

协程,立足于函数,就是在函数上做了改造,它可以实现“让路”。那如何对这个函数进行改造呢?主要的改造有以下几点:

(1)不用return返回值,取而代之用yield返回中间的结果,其后就可以让路。return用于函数的一气呵成之后的最终返回结果,而yield用于让路之前返回结果。

(2)通常情况下,定义函数define do()之后,调用函数do()之后,将一气呵成返回最终结果,而改造之后,调用函数do()之后,函数不再立即执行,而是函数被包装成一个生成器。整个生命周期是这样的:定义函数a->调用函数a->函数包装成生成器A->激活生成器A,执行半路然后返回结果完成让路->执行其他函数b->再次激活生成器A->生成器A从上次让路的地方继续往下执行

函数的让路就是协程。关于协程的代码演示请见下面所示。此处是Python代码,但不影响非Python用户的理解,因为本文主要是从函数的角度进行分析,函数的通用规范在各种语言中大同小异,例如使用return返回值,中间不能暂停等等通用规范。

4、函数和协程小结

协程的本质就是函数,是跑在一个线程里面的,是函数的让路,无关乎CPU时间片的调用。

协程的创建本质就是普通函数的创建,非常轻量级,从而使你可以在一个线程里面轻松创建数十万个协程,就像数十万次函数调用一样。可以想象一下,如果是在一个进程里面创建数十万个线程,结果该是怎样可怕。

综之,认识到协程的本质就是函数,这样才能更好的明白协程。

    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。如发现有害或侵权内容,请点击这里 或 拨打24小时举报电话:4000070609 与我们联系。

    猜你喜欢

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多
    喜欢该文的人也喜欢 更多