最近越来越认为,在讲解技术相关问题时,大白话固然很重要,通俗易懂,让人有想读下去的欲望。但几乎所有的事,都有两面性,在看到其带来好处时,不妨想想是否也引入了不好的地方。

例如在博客中,过于大白话的语言的确会让你阅读起来更加顺畅,也更容易理解。但这都是其他人理解,已经咀嚼过了的,人家是已经完全理解了,你从这些信息中大概可能会观察不到全貌。所以,适当的白话是很好的,但这个度得控制一下。

接下来切入正文。

相信大家经常看到这个问题:

BIO、NIO 和 AIO 有什么区别?

看到这个问题,可能你脑海中就会浮现以下这些字眼。比如 BIO 就是如果从内核获取数据会一直阻塞,直到数据准备完毕返回。再比如 NIO,内核在数据没有准备好时不会阻塞住,调用程序会一直询问内核数据是否 Ready。

虽然是正确的,字数也很少。但是这样一来,你看这些概念就不是理解,而是背诵了。其实 BIO 和 NIO 这类的名词还有一个共同的名字叫——IO模型,总共有:


IO 模型

由于信号驱动 IO 在实际中不常用,我们主要讲以下四种模型:

  1. 同步阻塞
  2. 同步非阻塞
  3. IO 多路复用
  4. 异步 IO

这里还是通过例子来理解这 4 种 IO 模型:

假设此时客户端正在发送一些数据到服务器,并且数据已经通过客户端的协议栈、网卡,陆陆续续的到达了服务器这边的内核态 Buffer 中了。

不清楚用户态和内核态区别的可以看看《简单聊聊用户态和内核态的区别》

对数据在网络中是如何传输的细节感兴趣的,可以去看看我之前写的文章 《请求数据包从发送到接收,都经历了什么?》

同步阻塞 BIO

我们需要知道,内核在处理数据的时候其实是分成了两个阶段:

  • 数据准备
  • 数据复制

在网络 IO 中,数据准备可能是客户端还有部分数据还没有发送、或者正在发送的途中,当前内核 Buffer 中的数据并不完整;而数据复制则是将内核态 Buffer 中的数据复制到用户态的 Buffer 中去。

调用线程发起 read 系统调用时,如果此时内核数据还没有 Ready,调用线程会阻塞住,等待内核 Buffer 的数据。内核数据准备就绪之后,会将内核态 Buffer 的数据复制到用户态 Buffer 中,这个过程中调用线程仍然是阻塞的,直到数据复制完成,整个流程用图来表示就张这样:

同步非阻塞 NIO

相信大家知道 Java 中有个包叫 nio,但那跟我们现在正在讨论的 NIO 不是同一个概念。

现在正在讨论的是 Non-Blocking IO,代表同步非阻塞,是一种基础的 IO 模型。而 nio 包则是 New IO,里面的 IO 模型实际上是 IO多路复用,大家不要搞混淆了。

有了 BIO 的基础,这次我们直接来看图:


NIO

还是分为两个阶段来讨论。

数据准备阶段。此时用户线程发起 read 系统调用,此时内核会立即返回一个错误,告诉用户态数据还没有 Read,然后用户线程不停地发起请求,询问内核当前数据的状态。

数据复制阶段。此时用户线程还在不断的发起请求,但是当数据 Ready 之后,用户线程就会陷入阻塞直到数据从内核态复制到用户态

稍微总结一下,如果内核态的数据没有 Ready,用户线程不会阻塞;但是如果内核态数据 Ready 了,即使当前的 IO 模型是同步非阻塞,用户线程仍然会进入阻塞状态,直到数据复制完成,并不是绝对的非阻塞。

那 NIO 的好处是啥呢?显而易见,实时性好,内核态数据没有 Ready 会立即返回。但是事情的两面性就来了,频繁的轮询内核,会占用大量的 CPU 资源,降低效率

IO 多路复用

IO 多路复用实际上就解决了 NIO 中的频繁轮询 CPU 的问题。在之前的 BIO 和 NIO 中只涉及到一种系统调用——read,在 IO 多路复用中要引入新的系统调用——select

read 用于读取内核态 Buffer 中的数据,而 select 你可以理解成 MySQL 中的同名关键字,用于查询 IO 的就绪状态。

在 NIO 中,内核态数据没有 Ready 会导致用户线程不停的轮询,从而拉满 CPU。而在 IO 多路复用中调用了 select 之后,只要数据没有准备好,用户线程就会阻塞住,避免了频繁的轮询当前的 IO 状态,用图来表示的话是这样:


IO 多路复用

异步 AIO

该模型的实现就如其名,是异步的。用户线程发起 read 系统调用之后,无论内核 Buffer 数据是否 Ready,都不会阻塞,而是立即返回。

内核在收到请求之后,会开始准备数据,准备好了&复制完成之后会由内核发送一个 Signal 给用户线程,或者回调用户线程注册的接口进行通知。用户线程收到通知之后就可以去读取用户态 Buffer 的数据了。


AIO

由于这种实现方式,异步 IO 有时也被叫做信号驱动 IO。相信你也发现了,这种方式最重要的是需要 OS 的支持,如果 OS 不支持就直接完蛋。

Linux 系统在 2.6 版本的时候才引入了异步IO,不过那个时候并不算真正的异步 IO,因为内核并不支持,底层其实是通过 IO 多路复用实现的。而到了 Linux 5.1 时,才通过 io_uring 实现了真 AIO。

欢迎微信搜索关注【SH的全栈笔记】,如果你觉得这篇文章对你有帮助,还麻烦点个赞关个注分个享留个言

图解四种 IO 模型的更多相关文章

  1. 四种IO模型

    四种 IO 模型:       首先需要明确,IO发生在 用户进程 与 操作系统 之间.可以是客户端IO也可以是服务器端IO. 阻塞IO(blocking IO):     在linux中,默认情况下 ...

  2. Linux五种IO模型(同步 阻塞概念)

    Linux五种IO模型 同步和异步 这两个概念与消息的通知机制有关. 同步 所谓同步,就是在发出一个功能调用时,在没有得到结果之前,该调用就不返回.比如,调用readfrom系统调用时,必须等待IO操 ...

  3. 漫谈五种IO模型

    阅读目录 1 基础知识回顾 2 I/O模式 3 事件驱动编程模型 网络编程里常听到阻塞IO.非阻塞IO.同步IO.异步IO等概念,搞清楚这些概念之前,还得先回顾一些基础的概念. 1 基础知识回顾 注意 ...

  4. Linux 网络编程的5种IO模型:多路复用(select/poll/epoll)

    Linux 网络编程的5种IO模型:多路复用(select/poll/epoll) 背景 我们在上一讲 Linux 网络编程的5种IO模型:阻塞IO与非阻塞IO中,对于其中的 阻塞/非阻塞IO 进行了 ...

  5. Linux 网络编程的5种IO模型:异步IO模型

    Linux 网络编程的5种IO模型:异步IO模型 资料已经整理好,但是还有未竟之业:复习多路复用epoll 阅读例程, 异步IO 函数实现 背景 上一讲< Linux 网络编程的5种IO模型:信 ...

  6. 正确理解这四个重要且容易混乱的知识点:异步,同步,阻塞,非阻塞,5种IO模型

    本文讨论的背景是Linux环境下的network IO,同步IO和异步IO,阻塞IO和非阻塞IO分别是什么 概念说明 在进行解释之前,首先要说明几个概念: - 用户空间和内核空间 - 进程切换 - 进 ...

  7. (四)五种IO模型

    基本概念 我们之前编写的套接字程序都是阻塞式的,其实这也是默认的形式.现在我们需要明确一些概念: 用户空间和内核空间 首先要明确,用户启动的应用程序在系统中以一个进程的形式存在,而无论对于网络数据还是 ...

  8. Atitit  五种IO模型attilax总结 blocking和non-blocking synchronous IO和asynchronous I

    Atitit  五种IO模型attilax总结 blocking和non-blocking synchronous IO和asynchronous I   1.1. .3 进程的阻塞1 1.2. 网络 ...

  9. 聊聊 Linux 中的五种 IO 模型

    本文转载自: http://mp.weixin.qq.com/s?__biz=MzAxODI5ODMwOA==&mid=2666538919&idx=1&sn=6013c451 ...

随机推荐

  1. 锁对象-条件对象-synchronized关键字

    1 import java.util.concurrent.locks.Condition; 2 import java.util.concurrent.locks.Lock; 3 import ja ...

  2. Initialization of data members

    In C++, class variables are initialized in the same order as they appear in the class declaration. C ...

  3. navicat突然连接不上远程linux服务器上的mysql

    我linux服务器上的mysql是docker安装的,突然有一天我的navicat连接不上服务器上的mysql,于是开始了下面一系列的修复 1.首先登录服务器上mysql,看是否能正常登录,我发现不能 ...

  4. 【Spring Framework】Spring入门教程(五)AOP思想和动态代理

    本文主要讲解内容如下: Spring的核心之一 - AOP思想 (1) 代理模式- 动态代理 ① JDK的动态代理 (Java官方) ② CGLIB 第三方代理 AOP概述 什么是AOP(面向切面编程 ...

  5. idea集成开发工具快捷键大全

    1  执行(run)                                                 alt+r 2  提示补全 (Class Name Completion)    ...

  6. 1.Java语言基础

    一:java语言介绍 (1). 1991年出现,1995年5月正式发布 出生地:SUN  创始人:James Gosling  2009年4月被Oracle收购 目前最新的版本2018年3月v10.0 ...

  7. 【C/C++】习题3-2 分子量/算法竞赛入门经典/字符串

    给出一种物质的分子式,求分子量.只包含4种原子,分别为C,H,O,N. [知识点] 1.ASCII码 [阿拉伯数字]48~57 [大写字母]65~90 [小写字母]97~122 2.输入循环到n-1的 ...

  8. 云原生应用管理,像管理手机APP一样管理企业应用

    我们在使用智能手机的时候,手机APP从应用市场一键安装,安装好即点即用,当有新版本一键升级,如果不想用了长按图标删除,整个过程非常简单,小朋友都能熟练掌握.而对于企业应用,由于结构复杂.可用性要求高. ...

  9. Mysql资料 数据类型

    目录 一.类型 整型 浮点型 定点数 字符串 二进制数据 时间日期类型 二.长度和范围 三.使用建议 原则 存储引擎 text和blob 浮点数和定点数 四.属性 一.类型 整型 取值范围如果加了un ...

  10. 追踪工具strace

    目录 一.简介 二.例子 找出程序读取的文件 查看现在程序在做什么 查看程序中哪个部分消耗大量cpu 无法连接服务器查看信息 一.简介 Linux 操作系统有很多用来跟踪程序行为的工具,内核态的函数调 ...