【从头到脚】并发编程(二)面试官问我Linux的网络IO模式怎么办?

方木Rudy 2020/5/28 17:26:02

该冲啦 老哥们,又到了该冲的时候啦 上一期我们聊了 「进程,线程和协程分别是什么,为什么使用它们以及它们之间的区别」(想看的小伙伴在这里)今天我们把目光放高一点,来看看进程,线程和协程的应用 --- 并发编程 并发编程 并发,顾名思义就是多个程序一起运行。运行…

该冲啦

老哥们,又到了该冲的时候啦

上一期我们聊了 「进程,线程和协程分别是什么,为什么使用它们以及它们之间的区别」(想看的小伙伴在这里)今天我们把目光放高一点,来看看进程,线程和协程的应用 --- 并发编程

并发编程

并发,顾名思义就是多个程序一起运行。运行在哪里呢?当然是cpu

所以并发就是多个程序一起运行在cpu上咯?

no no no!就单个cpu而言,一次只能处理一个程序,之所以能够看起来「一起运行」,是因为操作系统采用了分时系统,什么时间片,调度算法啦,让程序交替式的在cpu上运行,看起来好像是一起运行一样(这里不展开了,后面再更新给大家)

所以这就是并发的全部意义吗?就是多个程序通过操作系统的调度交替运行,看起来像一起运行,所以称为并发?

当然不是,之所以称为并发编程,是因为它们有真正同时运行的地方。

回顾一下操作系统的基础知识。我们知道,操作系统是采用虚拟存储的,它的核心是内核,为了保护内核的安全,操作系统把虚拟空间划分成两部分,一部分是内核空间,一部分是用户空间,就像星空战舰上的指挥室一样。

这时候聪明的的你肯定就会发现一个问题

cpu运算的结果是放在内核空间的,而我们读取结果却是在用户空间,这就有一个数据从内核空间到用户空间的过程

没错,从操作系统层看程序运行时的数据流的话,是有 「等待数据 --- 数据拷贝到内核空间 --- cpu运算 --- 数据从内核空间拷贝到用户空间」 这几个过程的

程序运行时的数据流动过程
程序运行时的数据流动过程

并发,就发生在这几个过程中。

来一张经典的示意图

中间的部分就是并发的部分,只要保证cpu运算的过程是串行的,其他过程都可以并发执行。

我们把数据从「等待」到「拷贝到用户空间」称作一次 IO操作

其中,「等待数据 --- 数据拷贝到内核空间 --- cpu运算」叫做 数据准备阶段,「数据从内核空间拷贝到用户空间」叫做 数据拷贝阶段

Linux的网络I/O模式

没有实际应用的知识是没有灵魂的,同样,没有被面试官问起的知识点都是孤独的..

当我们兴高采烈地聊到这里时,面试官会笑眯眯的问你

好的,你来讲一下linux中有哪些网络io模式吧?

好吧算你狠。

Linux中有五种网络io模式,分别是

  • 阻塞 I/O
  • 非阻塞 I/O
  • I/O 多路复用
  • 信号驱动 I/O
  • 异步 I/O

其中因为 信号驱动 I/O 不常用,所以一般只要了解其他四种 I/O 模式

当我们掰着指头好不容易数出这五种模式时,刚才还昏昏欲睡的面试官突然眼睛一亮,皮笑肉不笑地对你说

不错嘛,那你来说说 阻塞/非阻塞 IO 和同步/异步 IO的区别吧?

搞我是吧

但既然人家问,咱也只能准备。要分清这四个概念,就要牢牢记住之前数据流动的过程

(再放一遍)

阻塞 I/O

用户空间因为不能直接访问内核空间,当他想要结果时需要发起一个 read调用

但数据的准备和计算是需要一个过程的。比如我们进行网络请求的时,数据还没有返回,这个过程需要等待,当数据返回后被拷贝到内核空间,经过一系列运算,最终拷贝到用户空间

进程发起调用后就一直等待,也就是阻塞状态

等到数据拷贝完成后,进程还不能运行,需要内核给一个 ok 的信号,告诉进程数据已经拷贝到你那里了,用户进程这才解除阻塞状态,愉快的运行起来。

所以很明显,阻塞 I/O的特点是内核返回数据拷贝完成的信号之前,进程一直被阻塞。也就是说阻塞其实包括两个阶段,一个是等待数据准备,一个是数据从内核空间拷贝到用户空间

ok,理解了阻塞 I/O 的调用过程后,接下来的I/O模式就很简单了

非阻塞 I/O

和「阻塞 I/O」不同的是。「非阻塞 I/O」的进程发起一个read调用时,如果内核的数据还没有准备好,它就会立刻返回一个error信号

从用户进程的角度讲,它发起一个read操作后,并不需要等待就马上得到了一个结果,当用户进程判断结果是一个error时,它知道数据还没有准备好,于是再次发送read调用,一遍又一遍地询问。

当内核运算完毕准备好数据,并且再次收到用户进程的调用时,它就马上把数据拷贝到用户空间里,然后返回ok信号

所以「非阻塞 I/O」的特点是,用户进程不断询问内核,数据好了没有

I/O 多路复用

「I/O 多路复用」实际上是「阻塞 I/O」的变种。

select,poll,epoll都是「I/O 多路复用」的机制,它的好处在于单个进程就可以同时处理多个网络连接的IO

单个进程处理多个网络连接??!

没错,比如select方法。用户进程先调用select方法,select干了两件事,一个是管理多个负责网络连接的socket,另一个是让内核监视socket的状态

当内核接收到socket返回的数据并运算完成后,select方法就会返回,这时用户进程再发起read调用,把数据从内核空间拷贝到用户空间里

需要注意的是,socket本身是非阻塞的,但整个用户进程是阻塞的。

这种阻塞包括两个阶段,一个是发起select方法等待socket返回数据时阻塞,另一个是等待数据从内核控件拷贝到用户空间时阻塞,从这就可以看出和「阻塞 I/O」其实是一样的

所以,「I/O 多路复用」的特点是一个进程可以同时等待多个信号,任意一个信号就绪时发起系统调用

异步 I/O

终于到最后一个啦,加油加油!

区别于上面几种I/O模式,「异步 I/O」是没有阻塞的

用户进程发起read调用之后,立刻就可以开始去做其它的事。内核会立刻返回,所以不会对用户进程产生任何阻塞。

当内核数据计算完成后,它会自动把数据拷贝到用户空间,然后再给用户进程发送一个信号,告诉它read调用完成了。所以用户进程并不是在收到ok信号后拷贝数据,数据拷贝阶段也不会阻塞

所以「异步 I/O」的特点是,用户进程不需要等待内核返回的信号,一直运行

总结

终于介绍完啦

总结一下

阻塞io和非阻塞io的区别是

内核准备数据时有没有立即返回

阻塞io只有在内核准备好数据后才返回,而非阻塞io在准备过程中一直返回。

同步io和异步io的区别

同步io会阻塞进程,异步io不会阻塞进程

所以其实「阻塞 I/O」,「非阻塞 I/O」和「I/O 多路复用」都是同步I/O

前面不够细心的小伙伴可能会问了

为什么「非阻塞 I/O」是同步I/O呢?

仔细看「非阻塞 I/O」的流程图

当内核的数据准备好后,用户进程再次询问时,数据开始从内核空间拷贝到用户空间。这个过程中用户进程是阻塞的,只有当拷贝完成,内核返回完成信号,进程才会继续运行。

所以,不管是「阻塞 I/O」还是「非阻塞 I/O」都是会发生阻塞

不同的是,「阻塞 I/O」在数据准备阶段和从内核空间拷贝到用户空间阶段都会阻塞,「非阻塞 I/O」只有在拷贝阶段会阻塞

结尾

到这里,我们了解了Linux主要的四种网络I/O模式,这是并发编程系列的第一篇文章,不知道这样子解释够不够简单清晰

每天我都会分享一篇关于「计算机基础」「操作系统」「python」「数据分析」相关的文章

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

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

感谢大家阅读到这里!!无以为谢,只能「砰砰砰」祝各位家庭幸福,天天开心 ~

随时随地学软件编程-关注百度小程序和微信小程序
关于找一找教程网

本站文章仅代表作者观点,不代表本站立场,所有文章非营利性免费分享。
本站提供了软件编程、网站开发技术、服务器运维、人工智能等等IT技术文章,希望广大程序员努力学习,让我们用科技改变世界。
[【从头到脚】并发编程(二)面试官问我Linux的网络IO模式怎么办?]http://www.zyiz.net/tech/detail-137653.html

上一篇:BuildRun低代码开发教程第五节 | 设备管理开发

下一篇:操作系统正确的学习姿势 --- 你不可错过的宝藏资源

赞(0)

共有 条评论 网友评论

验证码: 看不清楚?
    关注微信小程序
    程序员编程王-随时随地学编程

    扫描二维码或查找【程序员编程王】

    可以随时随地学编程啦!

    技术文章导航 更多>
    扫一扫关注最新编程教程