首页 > 编程开发 > 五种 IO 模型
2023
05-05

五种 IO 模型

1 单线程、任意创建线程与线程池的对比

分别使用单线程、任意创建线程的多线程以及线程池的方式实现一个简单的 HTTP Server,使用 Super Benchmark 对其进行压力测试。

单线程

五种 IO 模型 - 第1张  | Weiguang的博客

任意创建线程

五种 IO 模型 - 第2张  | Weiguang的博客

使用固定大小的线程池

五种 IO 模型 - 第3张  | Weiguang的博客

2 NIO 模型与相关概念

通信模型

阻塞、非阻塞:可以理解为做一件事情能否立即得到返回结果,能立即得到就是非阻塞,不能立即得到就是阻塞。
同步、异步:完成一系列任务,如果总是先做一件事情,再做下一件事情就是同步模型;可以同时做几件事情,不用等一件事做完再去做另一件事,就是异步模型。
有什么关系和区别?

  • 同步异步是通信模式。
  • 阻塞、非阻塞是线程处理模式。

五种IO 模型

我们的应用程序是在用户空间中运行的,它不存在实质的 IO 过程,真正的 IO 是在操作系统中进行的。针对网络IO的操作,可以分成两个阶段,IO 调用阶段和 IO 执行阶段。

  • IO 调用是由进程向操作系统发送一次 IO 请求。
  • IO 执行是由操作系统内核来完成的,数据准备好之后从内核缓冲区拷贝到用户进程缓冲区。

五种 IO 模型 - 第4张  | Weiguang的博客

阻塞式IO、BIO

五种 IO 模型 - 第5张  | Weiguang的博客

用户线程从发起读请求到读完成的这段时间一直被阻塞,线程资源被浪费。

  • 优点: 实现简单。

  • 缺点: 需要为每一个连接的IO配备一个线程,在高并发应用场景下,需要大量的线程来维护大量的网络连接,内存、线程切换开销会十分巨大。

非阻塞式IO

五种 IO 模型 - 第6张  | Weiguang的博客

在第一阶段,用户线程采用轮询的方式询问内核数据是否准备好,内核如果没有准备好直接返回错误码,在轮询的间隙不占用线程资源。在第二阶段拷贝数据的时候,用户线程依然是阻塞的。

  • 优点: 每次发起的IO系统调用,在内核等待数据过程中可以立即返回。用户线程不会阻塞,实时性较好。
  • 缺点: 需要不断的进行系统调用轮询,测试数据是否准备好,将占用大量的CPU时间,效率低下。

IO 多路复用(IO multiplexing),也称事件驱动IO(event-driven IO)

五种 IO 模型 - 第7张  | Weiguang的博客

五种 IO 模型 - 第8张  | Weiguang的博客

在单个线程里同时监控多个套接字,通过select 或poll 轮询所负责的所有socket,当某个socket 有数据到达了,就通知用户进程。
IO 复用同非阻塞IO 本质一样,不过利用了新的select 系统调用,由内核来负责本来是请求进程该做的轮询操作。看似比非阻塞IO 还多了一个系统调用开销,不过因为可以支持多路IO,才算提高了效率。进程先是阻塞在select/poll 上,再是阻塞在读操作的第二个阶段上。

  • 优点: 使用一个查询就绪状态的线程就可以同时同时轮询成千上万个连接。系统不必要创建和维护大量的线程,大大减小了系统的开销。
  • 缺点: select/epoll 调用都是阻塞式的,属于同步IO。都需要在读写事件就绪后,由系统调用本身负责进行读写,也就是这个读写过程是阻塞的。
select/poll 的几大缺点:

(1)每次调用select,都需要把fd 集合从用户态拷贝到内核态,这个开销在fd 很多时会很大
(2)同时每次调用select 都需要在内核遍历传递进来的所有fd,这个开销在fd 很多时也很大
(3)select 支持的文件描述符数量太小了,默认是1024

epoll(Linux 2.5.44内核中引入,2.6内核正式引入,可被用于代替POSIX select 和poll 系统调用):

(1)内核与用户空间共享一块内存
(2)通过回调解决遍历问题
(3)fd 没有限制,可以支撑10万连接

信号驱动I/O

五种 IO 模型 - 第9张  | Weiguang的博客

信号驱动IO 与BIO 和NIO 最大的区别就在于,在IO 执行的数据准备阶段,不需要轮询。
如图所示:当用户进程需要等待数据的时候,会向内核发送一个信号,告诉内核我要什么数据,然后用户进程就继续做别的事情去了,而当内核中的数据准备好之后,内核立马发给用户进程一个信号,说”数据准备好了,快来查收“,用户进程收到信号之后,立马调用 recvfrom ,去查收数据。

  • 优点: 在第一阶段不使用轮询,而是使用信号的方式。
  • 缺点: 第二阶段依然是阻塞的。

异步式IO

异步IO 真正实现了IO 全流程的非阻塞。用户线程发起系统调用之后立即返回,用户线程不必在这里等待。当内核将数据准备好之后,将数据从内核缓冲区拷贝到用户进程缓冲区,然后发送信号通知用户线程来处理。

  • 优点: 在内核等待数据和复制数据的两个阶段,用户线程都不是阻塞的。
  • 缺点: 需要操作系统底层内核提供支持。
最后编辑:
作者:lwg0452
这个作者貌似有点懒,什么都没有留下。
捐 赠如果您觉得这篇文章有用处,请支持作者!鼓励作者写出更好更多的文章!

留下一个回复

你的email不会被公开。