---
title: IO 模型
date: 2022-02-03
tags:
- IO模型
categories:
- 后端 Back-end
isShowComments: true
---

<Boxx/>

[[toc]]

借用知乎用于 Levin 的回答，对各种模型讲个故事，描述下各个IO模型的区别。

## 简单理解各IO模型

故事情节为：老李去买火车票，三天后买到一张退票。参演人员（老李，黄牛，售票员，快递员），往返车站耗费1小时。

### 1. 阻塞IO模型

老李去火车站买票，排队三天买到一张退票。

耗费：在车站吃喝拉撒睡 3天，其他事一件没干。

### 2. 非阻塞IO模型

老李去火车站买票，隔12小时去火车站问有没有退票，三天后买到一张票。

耗费：往返车站6次，路上6小时，其他时间做了好多事。

### 3. IO复用模型

- select/poll（有selector选择器，去轮询选择器）

老李去火车站买票，委托黄牛，然后每隔6小时电话黄牛询问，黄牛三天内买到票，然后老李去火车站交钱领票。 

耗费：往返车站2次，路上2小时，黄牛手续费100元，打电话17次

- epoll（事件回调）

老李去火车站买票，委托黄牛，黄牛买到后即通知老李去领，然后老李去火车站交钱领票。 

耗费：往返车站2次，路上2小时，黄牛手续费100元，无需打电话

### 4. 信号驱动IO模型

老李去火车站买票，给售票员留下电话，有票后，售票员电话通知老李，然后老李去火车站交钱领票。  

耗费：往返车站2次，路上2小时，免黄牛费100元，无需打电话

### 5. 异步IO模型

老李去火车站买票，给售票员留下电话，有票后，售票员电话通知老李并快递送票上门。 

耗费：往返车站1次，路上1小时，免黄牛费100元，无需打电话

## 总结

1同2的区别是：自己轮询

2同3的区别是：委托黄牛

3同4的区别是：电话代替黄牛

4同5的区别是：电话通知是自取还是送票上门

- 阻塞IO模型：单线程一直阻塞直到事件发生才处理，期间干不了其他事情

- 非阻塞IO模型：while(true) 不断循环看有没有事件发生才处理，期间可以干其他事情，但是需要自己不断的去监测

- IO复用模型：基于事件驱动（类似与页面的一个button一个事件），有事件发生才处理，期间可以干其他事情，可以理解有一个中间人selector替我们监听，
有事件后通知我们去处理

|                     | 同步阻塞IO | 伪异步IO   | NIO         | AIO          |
| ------------------- | ---------- | ---------- | ----------- | ------------ |
| 客户端数目 ：IO线程 | 1 : 1      | m : n      | m : 1       | m : 0        |
| IO模型              | 同步阻塞IO | 同步阻塞IO | 同步阻塞IO | 异步非阻塞IO |
| 吞吐量              | 低         | 中         | 高          | 高           |
| 编程复杂度          | 简单       | 简单       | 非常复杂    | 复杂         |


## 结合实际场景，理解同步、异步、阻塞、非阻塞的两两组合

### 同步阻塞（Synchronous Blocking）

买票者在售票窗口排队等待购票，当轮到自己时，**提交购票请求并等待**售票员完成购票操作后才能继续下一步操作。

在这个过程中，买票者是同步等待售票操作的完成，阻塞其他任务的执行。

- 同步：提交购票请求后，等待请求结果。
- 阻塞：一直在窗口等着。

### 同步非阻塞（Synchronous Non-blocking）

买票者向售票窗口提交购票请求后，**不需要等待售票员立即返回结果**，而是离开售票窗口进行其他任务。

买票者会**定期回来询问**售票员购票的进度，直到购票操作完成并获取购票结果。

在这个过程中，买票者是同步地等待售票结果，但不会阻塞其他任务的执行。

- 同步：提交购票请求后，等待请求结果。
- 非阻塞：等待请求结果期间，可以去接个水，回来看看有没有结果；泡个面，回来看看有没有结果；上个WC，回来看看有没有结果。

### 异步阻塞（Asynchronous Blocking）

买票者向售票窗口提交购票请求后，不需要等待售票员立即返回结果，而是离开售票窗口进行其他任务。

售票员在购票操作完成后，主动通知买票者购票结果。

但是买票者需要**等待售票员的通知**（通知后自己去取票），这是一个阻塞操作，但期间可以进行其他任务。

- 异步：提交购票请求后，直接回老家干活去了。
- 阻塞：等待通知，然后自己去取票。

### 异步非阻塞（Asynchronous Non-blocking）

买票者向售票窗口提交购票请求后，不需要等待售票员立即返回结果，而是离开售票窗口进行其他任务。

售票员在购票操作完成后，通过回调函数或事件通知买票者购票结果（直接快递到家）。

买票者**无需等待售票员的通知**，可以继续执行其他任务，而在购票结果准备好时，会触发回调函数或处理事件（直接快递到家）。

- 异步：提交购票请求后，直接回老家干活去了。
- 非阻塞：无需等待通知，直接快递到家。

### IO多路复用（IO Multiplexing）

火车站设置了一个信息显示屏，上面显示了可用车票的信息。

买票者可以自由地观察信息显示屏上的车票情况，无需排队等待。一旦有票可用，买票者可以立即前往指定窗口进行购票。

多个售票窗口的状态由系统进行监控和管理，买票者只需关注信息显示屏上的变化即可，避免了排队等待的阻塞。

## 实际场景总结

在火车站买票的场景中：

同步阻塞模型是提交购票请求并一直等待，同步非阻塞模型允许买票者在等待购票结果时做其他事情。

异步阻塞模型中买票者需要等待售票员的通知，而异步非阻塞模型中买票者无需等待售票员通知，可以继续执行其他任务。

而IO多路复用模型通过信息显示屏的方式，使买票者可以观察多个窗口的状态，选择合适的窗口购票，避免了排队等待的阻塞。

## 参考

- [BIO、NIO、Netty示例demo](https://blog.csdn.net/u013374645/article/details/82808301)

<Reward/>
