当前位置:   article > 正文

io等待为什么引发cpu过高_面试官问我Linux的网络IO模式怎么办?

大量线程等待io cpu高

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

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

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

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

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

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

25c5d9135be3b59f7d0165ddfb964231.png

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

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

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

2686c6d8daec58ac704b43480de66902.png

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

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

来一张经典的示意图

8b3922ba63d0b28d5d61e336e493d0a5.png

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

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

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

aa894314acf810927a9b21363051cf22.png

Linux的网络I/O模式

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

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

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

6cee2b130494dca372316d54cd1bd438.png

好吧算你狠。

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

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

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

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

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

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

(再放一遍)

1365258ad05c1ff473356cf4f79e7371.png

阻塞 I/O

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

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

bc422362e49b9e09515f351957c9fa7b.png

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

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

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

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

非阻塞 I/O

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

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

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

544915e4183bba1212532fe9c75d55e9.png

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

I/O 多路复用

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

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

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

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

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

26a9410d62de69053466ae151b0d7425.png

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

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

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

异步 I/O

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

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

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

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

3b3a3752f35f454088d51ae09d37d4de.png

所以「异步 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」只有在拷贝阶段会阻塞。


作者:方木Rudy
链接:https://juejin.im/post/5ece31e6e51d4578a51f7bf4

声明:本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:【wpsshop博客】
推荐阅读
相关标签
  

闽ICP备14008679号