【从头到脚】开开心心的认识进程,线程和协程

兄弟们上车啦

准备好上车了吗?

GO!

我们天天被叫「程序员」,有个万物起源类型的问题

程序是什么?

抛开那些拗口的定义,程序给我们最直观的感受就是 「应用」

微信是应用,网页是应用,后台也是一个提供服务的大型应用

进程和线程

那如果问你进程和线程是什么?该怎么描述?

这种问烂的问题,随便一搜就有很多

搜索引擎总是把我不懂的东西用一种更不懂的方式讲出来,除了让我手忙脚乱查查查,剩下的就是对大佬的世界的恐慌 QAQ

如果是按我自己的理解,进程和线程好像都差不多,都是 「执行任务的过程」

说其然就要说其所以然,啥叫「执行任务」呢?

扫描二维码关注公众号,回复: 11270621 查看本文章

我们都知道,cpu是计算机的运算核心,程序都是在cpu上运行的,「执行任务」也很简单,就是程序在cpu上运行的过程,换句话说,是程序占用cpu的时间

所以进程和线程,都是程序占用CPU运算时间的过程

这差不多是比较符合我们学习时候的一个定义了

那么问题来了,既然干的事都差不多,为啥还要分进程线程呢?比方说多线程的场景我就用多进程解决,不行吗?

不错不错,小伙子你很有探(gang)究(jing)精神,我看好你

直接查这个问题的话,很多回答会告诉你,因为线程比进程简单,进程间通信是IPC,进程切换的时候开销大巴拉巴拉...

那为什么说线程就简单了呢?

从「占用CPU运算时间」的角度可能不好解释

这时候需要我们回想一点操作系统的基础知识。如果我们笼统来说,操作系统就是由许多进程组成的一个整体,也就是说,进程是操作系统划分出来的一小部分,划分的时候你总要给点东西吧,给的这些东西就是 「资源」,比如地址空间,数据栈等等。不同的进程就像我们手机里不同的应用,彼此之间是相对独立的。

这种独立是比较严格的,毕竟抖音总不能随随便便就知道你微信里的好友吧,如果可以的话也不用头疼微信的封锁了 = =

如果把操作系统比作一个巨大的「应用」,既然他需要不同的进程来执行不同的「小应用」,那我们类比一下,一个「小应用」里会不会也需要类似的东西执行不同的「功能」呢?

答案当然是肯定的,聪明的你肯定也知道是 线程 了。这就是线程的意义,线程是基于进程存在的,对进程来说,我划分一个线程没必要像操作系统一样考虑很多东西,这就相当于把操作系统划分进程的过程简单化了,所以线程天然从设计上老说就要更简单,更方便

看到这里,可能有小伙伴发现了一个关键词 「资源」

没错,操作系统划分进程的时候要给资源,相对的,进程划分线程的时候也要给资源。他们有什么不同呢?

根据我们之前的解释,不同进程之间的独立性很强,这就意味着一个进程不能轻易访问另一个进程的资源。但线程就不一样了,我大微信的朋友圈读一下旁边的通讯录怎么了?所以线程之间资源的共享和通信很容易。

但容易归容易,这也带来了另一个问题,那就是多线程访问资源的同步问题。为了解决同步问题,引入了同步机制,于是就有了我们常见到的锁,条件变量,信号量,临界资源,共享变量这些概念(这就是后面文章的内容了)

成了,联系起来了!

这时候我们再喊出那句脍炙人口的话

进程是资源分配的最小单位!

线程是CPU调度的最小单位!

是不是就容易理解多了?

到现在为止,你应该对「进程和线程」有了一个较为整体的理解了,不知道这种描述够不够通俗易懂。

协程

再接再厉,我们来了解一下 「协程」 。别担心,很简单的

随着计算机的发展,那帮不安分的大佬们又有了新心思。你看啊,我操作系统分出了进程,进程分出了线程,那线程是不是也....

妥了,明白了!

这样理解是可以的。如果用类比方式的话,单线程确实也可以分成「多协程」,但与进程和线程不同的是,进程和线程的控制者是操作系统,而协程的控制者是程序本身,说白了就是各种语言。这就是为什么协程这个概念在一些语言中很少被提及,比如java,因为协程的实现者是程序,只有人开发出来,放到语言的标准中才能被使用。(现在已经有用java实现的协程库,比如Quasar和ea-async)

那么问题又来了,跟我们刚刚了解线程一样,有了线程,为什么还要实现协程呢?

「线程→协程」「进程→线程」 的发展过程是一样的,都是为了更快,更轻量的实现我们的开发目标。既然有了协程,那就意味着线程是相对「不快,不轻量的」,表现在我们头疼的各种锁,同步以及切换线程时的开销。而通常我们要实现的需求很简单,就是网络请求等待数据返回,或者读写数据库而已,这种程度的计算对cpu来说是小菜一碟,cpu在0.000001秒早就把它该计算的计算完了,就因为你网络请求超时,数据库慢腾腾的写数据不得不开个线程专门等你,实际上是大炮打蚊子的事情。

所以大佬们一拍脑袋

简单点,别整那些花里胡哨的!我们就用一个线程,一个cpu,先解决这些占使用场景80%的问题!

于是一顿哼哧哼哧,「协程」 就搞出来了

所以就有了那句枯燥的定义「协程是一个函数,它可以暂停它的执行,直到给定的指令完成」

既然我们知道了协程是什么,为什么来的,怀着探究的精神,当然得了解一下协程的实现原理了

刚刚说协程其实是语言层面的实现,所以各种语言具体的实现方式也是有一定差别的,大体上协程是基于事件驱动模型来实现的,关于事件驱动的原理其实非常简单,他的核心是事件循环,你就把它理解成一个无限循环

以js为例,当我们开开心心的执行同步代码时,如果突然遇到一个需要异步执行的事件,这时候js跟你说:

不慌,不就是异步事件嘛,我先帮你把它记录你下,你照常执行吧。

然后我们就照常直接后面的代码。

当我们同步的代码全部执行完时,事件循环还在可怜巴巴的一直问,可是已经没有同步的代码了,这时候js想起之前记录的异步事件,赶快执行完它,然后把结果告诉事件循环,事件循环的询问终于有了一次回应,开心的把结果输出

这就是协程原理的一个简单过程,当然这里面还有许许多多值得挖掘的地方,这里就不展开了,后面我会再写一篇文章详细介绍 ~

到现在为止,我们以一个探索者的视角,从头到尾认识了一遍进程、线程和协程,围绕这三个概念,但还有许许多多的东西值得说,比如并发,线程切换,多路IO复用,还有我们头疼的各种锁,一些有趣的事也是因为这些发生的,比如python是如何被人诟病是“单线程”的语言的,等等等等

总结

技术不应该是复杂枯燥的,只是一个知识点的掌握往往需要联系许许多多零碎的知识。我希望能够把这些知识有条理的组织起来,以一个探索者的视角,清晰的整理给大家

如果你喜欢的话,欢迎点个 ,如果你不小心 关注 了话,我保证后面会有更多有意思的东西更新给你~

如果你无感甚至不喜欢的话...

大哥!你就点个赞再走撒!!我上有老下有小,体弱多病身残志坚,你就点个赞好人一生平安呜呜呜 QAQ

哈哈,开个玩笑,祝大家天天开心 ~

猜你喜欢

转载自juejin.im/post/5ecc8149f265da77135a03ec