一文彻底搞定(阻塞/非阻塞/同步/异步)网络IO、并发编程模型、异步编程模型的爱恨情仇

概述#

是否和我有一样的困惑。什么阻塞 IO、非阻塞 IO、同步 IO、异步 IO,多路复用 (epoll) 等本质还是同步 IO,这时可能你和我一样懵逼多路复用是同步的 IO,那么使用 epoll 的 nginx、redis、swoole 等服务端程序又是异步的,这不前后矛盾么?网上文章又是五花八门,越看越糊涂。终于我无法忍受这样概念不清晰,乱麻一般的萦绕在我的心头。我决定要彻底拨开云雾见蓝天,啊!终于在一个阳光明媚的午后,就彻底顿悟了,这感觉如同德芙一般丝滑。今天就跟随我的步伐让你有丝滑一般的感觉,兄弟们走起来!!!!

网络 I/O#

IO:IO 是 input/ouput 英文缩写,顾名思义就是输入输出的意思,在计算中以 CPU 为视角,所有和外设 (键盘、显卡、网卡、打印机的等) 的数据操作都是涉及 IO 操作,外设流向 CPU 的是 input,流向外设的就是 ouput。网络 IO 就是网卡和 CPU 之间的数据交互。

思考一个问题:网卡数据流向 CPU 都经过哪些流程

一文彻底搞定(阻塞/非阻塞/同步/异步)网络IO、并发编程模型

数据流向示意图

用户进程发起一个网络 IO 操作的时候,大致上分为三个部分

  1. 用户进程读取数据,读取数据只会有三个可能 (有数据、没有数据、出错)
  2. 网卡数据从网卡外设到内核空间 (此过程现代计算机是不需要 CPU 参与,网卡控制器通过 DMA 技术直接搬运到内核空间)。数据完成空网卡控制器会发出中断信号。
  3. 数据到内核之后 CPU 负责复制 (在此我们先不考虑零拷贝情况) 到用户空间。

用户进程和内核交互围绕着 1 和 3 进行。到此在 1 和 3 环节就会有很多故事发生了。且听我慢慢道来!!!!

在给出分类之前我先抛出阻塞、非阻塞、异步、同步的定义,定义来自《UNIX 网络编程卷一 》的 6.2 章节
根据 POSIX 定义:

  • A synchronous I/O operation causes the requesting process to be blocked until that I/O operation completes (导致请求进程阻塞,直到 IO 操作完成)。
  • An asynchronous I/O operation does not cause the requesting process to be blocked (不导致请求进程阻塞)。

上述定义是说:如果在 1 阶段系统挂起用户进程,那么该 IO 操作就是阻塞 IO,反之不挂起,就是非阻塞 IO。如果在 2 阶段系统挂起用户进程,那么这次 IO 操作就是同步,反之不挂起就是异步。

有了上述的定义,我们如何尚方宝剑一样,在也不担心傻傻分不清网络 IO 相关晦涩难懂的概念了。就如同初中老师教会我们如何判断什么是化学反应变化是物理变化,判断标准就是看有无新的物质生成。我们判断网络分类标准就是如上述的定义。对,就是这么狭义!!!

操作针对上述 1 和 3 处理行为,我们将网络 IO 分类下列 5 类。

  • 阻塞 IO 此 IO 操作在 1 和 3 两个阶段,用户进程都在休眠状态
  • 非阻塞 I/O 此 IO 操作在 1 阶段未被挂起,3 阶段被挂起
  • 多路复用 I/O 此 IO 操作在 1 阶段 (select,poll) 被挂起、epoll 未挂起,3 阶段被挂起
  • 信号驱动 I/O 此 IO 操作在 1 阶段未挂起,的数据到从网卡到内核之后,CPU 通过信号机制通知用户进程。用户进程 3 阶段被挂起
  • 异步 I/O 此 IO 操作在 1 和 3 阶段都不需要用户进程参与,数据拷贝完成后 CPU 会通知用户进程

此刻来一张很经典的图

一文彻底搞定(阻塞/非阻塞/同步/异步)网络IO、并发编程模型

IO 对比图

从图中和上述定义就能看到真正的异步 IO 只有最后一个是。其余四个都是同步 IO。对于同步和异步深入理解,其实在 3 这个阶段 CPU 需要拷贝数据到用户空间,等于用户进程切换到内核空间去执行拷贝操作,这个时候用户进程只能被挂起等待 CPU 拷贝数据直到完成。用户进程被挂起这段时间,用户进程的后续代码都是无法执行的只能同步等待。

并发编程模型#

追求性能极致的程序员们,不遗余力地压榨 CPU。基于系统提供的网络 IO 模型,人类设计出形形色色的并发模型。

  • 阻塞 IO 这种是完美无法提供并发的能力,只能串行的去处理客户端连接,所以网络 IO 就有了新的发展,进入到了非阻塞 IO
  • 非阻塞 IO 这种 IO 模型 就能设计出多线程、多进程并发模型
  • 多路复用 这便是并发能力秘密武器,基于这种网络 IO 衍生出了 reactor 反应堆并发模型,大名鼎鼎的 nginx、redis 就是 reactor 模型
  • 信号驱动和异步 IO 暂时还未有更多的使用

异步编程模型#

在上述的并发模型中其实单纯靠多进程和多线程,还无法达到人们的预期。所以就有了异步编程模型,异步编程模型的宗旨就是,用户程序调用同步的网络 IO 模拟异步 IO。人们经常说的异步 IO 更多指的是 异步编程模型 (netty 就是典型的异步 IO)

在异步编程过有两个核心的技术技术回调和协程。

总结#

并非同步 IO 就会性能差,异步 IO 就会性能好。要具体情况而定!!!

本作品采用《CC 协议》,转载必须注明作者和本文链接
《L05 电商实战》
从零开发一个电商项目,功能包括电商后台、商品 & SKU 管理、购物车、订单管理、支付宝支付、微信支付、订单退款流程、优惠券等
《L01 基础入门》
我们将带你从零开发一个项目并部署到线上,本课程教授 Web 开发中专业、实用的技能,如 Git 工作流、Laravel Mix 前端工作流等。
讨论数量: 6

祝福你找到了自已的幸福,我还是一如既往的懵圈。

3年前 评论
arvin-hermit (楼主) 3年前

” 多路复用 I/O 此 IO 操作在 1 阶段 (select,poll) 被挂起、epoll 未挂起,3 阶段被挂起 “

这么说 epoll 应该是信号驱动 I/O?

3年前 评论
arvin-hermit (楼主) 3年前

感觉讲了,又感觉什么都没讲

3年前 评论
arvin-hermit (楼主) 3年前