关于IO的同步,异步,阻塞,非阻塞

上次写了一篇文章:Unix IO 模型学习。恰巧在此次周会的时候,@fp1203  (goldendoc成员之一) 正好在讲解poll和epoll的底层实现。中途正好讨论了网络IO的同步、异步、阻塞、非阻塞的概念,当时讲下来,你们的理解各不相同,互不相让。搜索了网络上的一些文章,观点也各不相同,甚至连wiki也将异步和非阻塞当成一个概念在解释。java

虽然网络上充斥了大量关于同步、异步、阻塞、非阻塞的文章,但大都是抄来抄去,没有一个权威的说法。但我找到了这一篇文章,该文章引用了《UNIX网络编程 卷1》的介绍,这本书的做者是Richard Stevens。若是有Richard Stevens在这方面的定义或者结论,那么我想,这应该是比较有说服力的了。node

关于《UNIX网络编程 卷1》这本书,我特地找了英文原版,也共享出来了:你们能够下载《UNIX网络编程 卷1》的英文原版(CHM格式)。编程

我看了6.2这节内容,这节内容就是讲IO模型的。刚刚提到的那篇文章,几乎就是翻译这个6.2节的。应该说,这个6.2节,对同步和异步的讲解,算是很清楚的。网络

下面是我本身理解的重点。异步

IO模型

目前unix存在五种IO模型(这也和上一篇文章:Unix IO 模型 中提到的一致),分别是:async

  • 阻塞型 IO(blocking I/O)
  • 非阻塞性IO(nonblocking I/O)
  • IO多路复用(I/O multiplexing)
  • 信号驱动IO(signal driven I/O)
  • 异步IO(asynchronous I/O)

IO的两个阶段

  1. 等待数据准备好
  2. 将数据从内核缓冲区复制到用户进程缓冲区

同步,异步的区别

那么究竟什么是同步和异步的区别呢?请重点读一下原文6.2节中的信号驱动IO和异步IO中的比较。最后总结出来是:函数

  • 同步IO,须要用户进程主动将存放在内核缓冲区中的数据拷贝到用户进程中。
  • 异步IO,内核会自动将数据从内核缓冲区拷贝到用户缓冲区,而后再通知用户。

这样,同步和异步的概念就很是明显了。以上的五种IO模型,前面四种都是同步的,只有第五种IO模型才是异步的IO。学习

阻塞和非阻塞

那么阻塞和非阻塞呢?注意到以上五个模型。阻塞IO,非阻塞IO,只是上面的五个模型中的两个。阻塞,非阻塞,是针对单个进程而言的。spa

当对多路复用IO进行调用时,好比使用poll。需注意的是,poll是系统调用,当调用poll的时候,其实已是陷入了内核,是内核线程在跑了。所以对于调用poll的用户进程来说,此时是阻塞的。.net

由于poll的底层实现,是去扫描每一个文件描述符(fd),而若是要对感兴趣的fd进行扫描,那么只能将每一个描述符设置成非阻塞的形式(对于用户进程来说,设置fd是阻塞仍是非阻塞,可使用系统调用fcntl),这样才有可能进行扫描。若是扫描当中,发现有可读(若是可读是用户感兴趣的)的fd,那么select就在用户进程层面就会返回,而且告知用户进程哪些fd是可读的。

这时候,用户进程仍然须要使用read的系统调用,将fd的数据,从内核缓冲区拷贝到用户进程缓冲区(这也是poll为同步IO的缘由)。

那么此时的read是阻塞仍是非阻塞呢?这就要看fd的状态了,若是fd被设置成了非阻塞,那么此时的read就是非阻塞的;若是fd被设置成了阻塞,那么此时的read就是阻塞的。

不过程序已经执行到了这时候,无论fd是阻塞仍是非阻塞,都没有任何区别,由于以前的poll,就是知道有数据准备好了才返回的,也就是说内核缓冲区已经有了数据,此时进行read,是确定可以将数据拷贝到用户进程缓冲区的。

但若是换种想法,若是poll是由于超时返回的,而咱们又对一个fd(此fd是被poll轮询过的)进行read调用,那么此时是阻塞仍是非阻塞,就很是有意义了,对吧!

结论

  1. 判断IO是同步仍是异步,是看谁主动将数据拷贝到用户进程。
  2. select或者poll,epoll,是同步调用,进行此调用的用户进程也处于阻塞状态。
  3. javaScript或者nodejs中的读取网络(文件)数据,而后提供回调函数进行处理,是异步IO。
相关文章
相关标签/搜索