美文网首页网络IOIPC
【再议IO】阻塞、非阻塞、同步、异步

【再议IO】阻塞、非阻塞、同步、异步

作者: LazzMan | 来源:发表于2017-04-19 00:10 被阅读135次

一、开胃菜

最近在学习Python中的socketserver时,从网上搜索了一下相关介绍,感觉它是socket IO复用+多线程的实现,但是度娘上大部分说它是socket 异步+多线程的实现,于是又再次度娘看了看网上各种介绍阻塞非阻塞IO同步异步IO的文章,感觉越看越乱,估计很多作者本身都没真正的去了解非阻塞与异步,经常将两个概念混淆,误导他人。

二、正餐

讲到网络编程的I/O模型,总会涉及到这几个概念。问了很多人,没几个能清晰地讲出他们之间的区别联系,甚至在网络上也有很多不同的观点,也不知是中国文字释义的博大精深,还是本来这几个概念就是绕人不倦。今天我也来给大家讲解一下我对这几个概念的理解。
既然网络上众说纷纭,不如找个权威参考一下,这个权威就是《UNIX网络编程:卷一》第六章——I/O复用。书中向我们提及了5种类UNIX下可用的I/O模型:

  • 阻塞式I/O;

  • 非阻塞式I/O;

  • I/O复用(select,poll,epoll...);

  • 信号驱动式I/O(SIGIO);

  • 异步I/O(POSIX的aio_系列函数);

阻塞式I/O模型:默认情况下,所有套接字都是阻塞的。怎么理解?先理解这么个流程,一个输入操作通常包括两个不同阶段:

(1)等待数据准备好;
(2)从内核向进程复制数据。

对于一个套接字上的输入操作,第一步通常涉及等待数据从网络中到达。当所有等待分组到达时,它被复制到内核中的某个缓冲区。第二步就是把数据从内核缓冲区复制到应用程序缓冲区。好,下面我们以阻塞套接字的recvfrom的的调用图来说明阻塞:

阻塞IO模型

标红的这部分过程就是阻塞,直到阻塞结束recvfrom才能返回。

非阻塞式I/O: 以下这句话很重要:进程把一个套接字设置成非阻塞是在通知内核,当所请求的I/O操作非得把本进程投入睡眠才能完成时,不要把进程投入睡眠,而是返回一个错误。看看非阻塞的套接字的recvfrom操作如何进行:

非阻塞式I/O模型

I/O多路复用:虽然I/O多路复用的函数也是阻塞的,但是其与以上两种还是有不同的,I/O多路复用是阻塞在select,epoll这样的系统调用之上,而没有阻塞在真正的I/O系统调用如recvfrom之上。如图:

I/O多路复用模型

我们阻塞与select调用,等待数据报套接字变为可读。当select返回套接字可读这一条件时,我们调用recvfrom把数据从内核缓冲区复制到应用程序缓冲区。
我们比较I/O复用与阻塞IO,I/O复用并不显得有什么优势,事实上由于使用select需要两个而不是单个系统调用,I/O复用还稍有劣势。但是,使用select的真正优势在于我们可以等待多个描述符就绪。

信号驱动式I/O:这种模型的优势在于等待数据报到达期间进程不被阻塞。 主循环可以继续执行,只要等待来自信号处理函数的通知。

信号驱动式I/O模型

异步I/O:这类函数的工作机制是告知内核启动某个操作,并让内核在整个操作(包括将数据从内核拷贝到用户空间)完成后通知我们。这种模型与信号驱动模型最大的区别在于:信号驱动式IO是由内核通知我们何时可以启动一个IO操作,而异步IO模型是由内核通知我们IO操作何时完成。如图:

异步I/O模型

三、加餐

1. 同步IO与异步IO的对比:

POSIX对这两个术语的定义:
同步I/O操作:导致请求进程阻塞,直到I/O操作完成;
异步I/O操作:不导致请求进程阻塞。

5种IO模型的对比

2. 自己的理解

  • 阻塞,非阻塞:进程/线程要访问的数据是否就绪,进程/线程是否需要等待;

  • 同步,异步:访问数据的方式,同步需要主动读写数据,在读写数据的过程中还是会阻塞;异步只需要I/O操作完成的通知,并不主动读写数据,由操作系统内核完成数据的读写

3. 留给你的问题

相信如果你认真看完了上面的内容,下面的几个概念你应该会明白了:

  • 同步阻塞IO ?
  • 同步非阻塞IO ?
  • 异步IO(异步有没有阻塞和非阻塞IO呢?)

四、夜宵

同步、异步、阻塞、非阻塞这几个概念,上面已经写得很清楚了。
这里我结合自己的理解,简单地聊一下为什么这几个概念容易混淆。如果有错误之处,恳请批评指正。
我认为同步、异步、阻塞、非阻塞,是分3个层次的:CPU层次线程层次程序员感知层次
这几个概念之所以容易混淆,是因为没有分清楚是在哪个层次进行讨论。

CPU层次
在CPU层次,或者说操作系统进行IO和任务调度的层次,现代操作系统通常使用异步非阻塞方式进行IO(也有少部分IO可能会使用同步非阻塞轮询(6-2的非阻塞IO模型)),即发出IO请求之后,并不等待IO操作完成,而是继续执行下面的指令(非阻塞),IO操作和CPU指令互不干扰(异步),最后通过中断的方式来通知IO操作完成结果。

线程层次
在线程层次,或者说操作系统调度单元的层次,操作系统为了减轻程序员的思考负担,将底层的异步非阻塞的IO方式进行封装,把相关系统调用(如read,write等)以同步的方式展现出来。然而,同步阻塞的IO会使线程挂起,同步非阻塞的IO会消耗CPU资源在轮询上。
为了解决这一问题,就有3种思路:

  • 多线程(同步阻塞);
  • IO多路复用(select,poll,epoll)(同步非阻塞,严格地来讲,是把阻塞点改变了位置,阻塞在select);
  • 直接暴露出异步的IO接口,如kernel-aio和IOCP(异步非阻塞)。

程序员感知层次
在Linux中, IO多路复用用得比较广泛,也是比较理想的解决方案。然而,直接使用select之类的接口,依然比较复杂,所以各种库和框架百花齐放,都试图对IO多路复用进行封装。
此时,库和框架提供的API又可以选择是以同步的方式还是异步的方式来展现。如python的asyncio库中,就通过协程,提供了同步阻塞式的API;如node.js中,就通过回调函数,提供了异步非阻塞式的API。

总结
因此,我们在讨论同步、异步、阻塞、非阻塞时,必须先明确是在哪个层次进行讨论。比如node.js,我们可以说她在程序员感知层次提供了异步非阻塞的API,也可以说在Linux下,她在线程层次以多路复用的epoll来实现。

广义上的异步:调用在发出之后,这个调用就直接返回了,所以没有返回结果。换句话说,当一个异步过程调用发出后,调用者不会立刻得到结果。而是在调用发出后,被调用者通过状态、通知来通知调用者,或通过回调函数处理这个调用

狭义上的异步:异步是一种访问数据的方式,异步只需要I/O操作完成的通知并不主动读写数据由操作系统内核完成数据的读写

广义上的同步:发出一个调用时,在没有得到结果之前,该调用就不返回。但是一旦调用返回,就得到返回值了

狭义上的同步:同步是一种访问数据的方式,同步需要主动读写数据,在读写数据的过程中会阻塞 (例:我们需要自己调用recvfrom将数据从内核缓冲读入应用缓冲,即需要主动读写)

阻塞:进程/线程要访问的数据未就绪,当前进程/线程会挂起

非阻塞:进程/线程要访问的数据未就绪,当前进程/线程不会挂起

五、谢谢厨子

怎样理解阻塞非阻塞与同步异步的区别?

相关文章

  • IO模型

    原文参考链接 四种状态 同步 异步 阻塞 非阻塞 IO分类 同步阻塞IO 同步非阻塞IO 异步非阻塞IO注意: 没...

  • 阻塞非阻塞 同步异步 IO模型及其应用 NIO实现原理

    1.同步异步概念 2.阻塞非阻塞概念 3.常见I/O模型:同步阻塞IO,同步非阻塞IO,异步阻塞IO,异步非阻塞I...

  • BIO NIO AIO

    BIO:同步阻塞IONIO:同步非阻塞IOAIO:异步非阻塞IO先弄清楚同步、异步,阻塞、非阻塞概念。 io操作分...

  • UNIX 的5种IO模型介绍

    IO模型同步、异步、阻塞、非阻塞socket阻塞与非阻塞,同步与异步 同步和异步 同步/异步主要针对C端-同步就像...

  • I/O模型

    一般来说I/O模型可以分为:同步阻塞,同步非阻塞,异步阻塞,异步非阻塞IO 同步阻塞IO:在此种方式下,用户进程在...

  • 【再议IO】阻塞、非阻塞、同步、异步

    一、开胃菜 最近在学习Python中的socketserver时,从网上搜索了一下相关介绍,感觉它是socket ...

  • Java IO

    Before IO 分为:同步、异步阻塞、非阻塞 同步和异步是目的,阻塞和非阻塞是实现方式。 一个IO操作其实分成...

  • I/O详解之BIO,NIO,AIO概念

    IO的方式通常分为几种,同步阻塞的BIO、同步非阻塞的NIO、异步非阻塞的AIO。 1.IO场景 同步阻塞IO(B...

  • 产品开发

    IO复用模型同步,异步,阻塞,非阻塞及实例详解 IO复用模型同步,异步,阻塞,非阻塞及实例详解数据库中间件 MyC...

  • java IO、NIO、AIO

    IO流(同步、阻塞) 、 NIO(同步、非阻塞) 、 NIO2(异步、非阻塞) 概述在我们学习Java的IO流之前...

网友评论

    本文标题:【再议IO】阻塞、非阻塞、同步、异步

    本文链接:https://www.haomeiwen.com/subject/pvgqzttx.html