IO多路复用

简介: IO多路复用

9.2 I/O 多路复用:select/poll/epoll | 小林coding (xiaolincoding.com)

【并发】IO多路复用select/poll/epoll介绍_哔哩哔哩_bilibili 讲的有一点错误,但是可以理解

IO多路复用——深入浅出理解select、poll、epoll的实现 - 知乎 (zhihu.com)

原始的TCP连接

TCP Socket 基本只能一对一通信,因为使用的是同步阻塞的方式,当服务端在还没处理完一个客户端的网络 I/O 时,或者 读写操作发生阻塞时,其他客户端是无法与服务端连接的。

使用多进程优化

种用多个进程来应付多个客户端的方式,可以同时处理多个连接,但是也有很大的缺点:

  • 连接数量(开辟的进程)有限
  • 进程占用系统资源较多
  • 进程间上下文切换的代价很重的,性能会大打折扣。

使用多线程优化

同进程里的线程可以共享进程的部分资源,比如文件描述符列表、进程空间、代码、全局数据、堆、共享库等,这些共享些资源在上下文切换时不需要切换,而只需要切换线程的私有数据、寄存器等不共享的数据,因此同一个进程下的线程上下文切换的开销要比进程小得多。

  • 虽说线程切换的上写文开销不大,但是如果频繁创建和销毁线程,系统开销也是不小的
  • 如果使用线程池的方式来避免线程的频繁创建和销毁,会产生多线程竞争

IO多路复用是什么?

在linux系统中,实际上所有的I/O设备都被抽象为了文件这个概念,一切皆文件。磁盘、网络数据、终端,甚至进程间通信工具管道pipe等都被当做文件对待

一个进程虽然任一时刻只能处理一个请求,但是处理每个请求的事件时,耗时控制在 1 毫秒以内,这样 1 秒内就可以处理上千个请求,把时间拉长来看,多个请求复用了一个进程,这就是多路复用,这种思想很类似一个 CPU 并发多个进程,所以也叫做时分多路复用。

我们熟悉的 select/poll/epoll 内核提供给用户态的多路复用系统调用,进程可以通过一个系统调用函数从内核中获取多个事件

I/O模型

  • 阻塞IO 这是最常用的简单的IO模型。阻塞IO意味着当我们发起一次IO操作后一直等待成功或失败之后才返回,在这期间程序不能做其它的事情。 阻塞IO操作只能对单个文件描述符进行操作,比如readwrite
  • 非阻塞IO 进程发起IO系统调用后,如果内核缓冲区没有数据,需要到IO设备中读取,进程返回一个错误而不会被阻塞;进程发起IO系统调用后,如果内核缓冲区有数据,内核就会把数据返回进程。
  • 信号驱动IO 当进程发起一个IO操作,会向内核注册一个信号处理函数,然后进程返回不阻塞;当内核数据就绪时会发送一个信号给进程,进程便在信号处理函数中调用IO读取数据。
  • 异步IO 当进程发起一个IO操作,进程返回(不阻塞),但也不能返回果结;内核把整个IO处理完后,会通知进程结果。如果IO操作成功则进程直接获取到数据。
  • IO多路复用 使用一个进程来维护多个 Socket ,有 select/poll/epoll三种方法

Select

  1. 将已连接的 Socket 都放到一个文件描述符集合
  2. 调用 select 函数将文件描述符集合拷贝内核里,使用遍历的方式,让内核来检查是否有网络事件产生
  3. 当检查到有事件产生后,将此 Socket 标记为可读或可写
  4. 再把整个文件描述符集合拷贝用户态
  5. 然后用户态还需要再通过遍历的方法找到可读或可写的 Socket,然后再对其处理

select 使用固定长度的 BitsMap,表示文件描述符集合,而且所支持的文件描述符的个数是有限制的,在 Linux 系统中,由内核中的 FD_SETSIZE 限制, 默认最大值为 1024,只能监听 0~1023 的文件描述符。

小结

  • 位图BitsMap的大小有限,能开辟的文件描述符少
  • 需要遍历文件描述符集合来找到可读或可写的 Socket,时间复杂度为 O(n)
  • 需要在用户态与内核态之间拷贝文件描述符集合

Poll

poll 不再用 BitsMap 来存储所关注的文件描述符,取而代之用动态数组,以链表形式来组织,突破了 select 的文件描述符个数限制,当然还会受到系统文件描述符限制。

小结

  • 相比select ,突破文件描述符个数限制,当时还会受到系统文件描述符限制。
  • 需要遍历文件描述符集合来找到可读或可写的 Socket,时间复杂度为 O(n)
  • 需要在用户态与内核态之间拷贝文件描述符集合

Epoll

  • 先用 epoll_create 创建一个 epoll对象 epfd该函数生成一个 epoll 专用的文件描述符。其中 epoll_create 依靠 eventpoll 这个结构体实现,其中中的几个成员的含义如下:
  • wq: 等待队列链表。软中断数据就绪的时候会通过 wq 来找到阻塞在 epoll 对象上的用户进程。
  • rbr: 红黑树。为了支持对海量连接的高效查找、插入和删除,eventpoll 内部使用的就是红黑树。通过红黑树来管理用户主进程accept添加进来的所有 socket 连接。
  • rdllist: 就绪的描述符链表。当有连接就绪的时候,内核会把就绪的连接放到 rdllist 链表里。这样应用进程只需要判断链表就能找出就绪进程,而不用去遍历红黑树的所有节点了。
  • 再通过 epoll_ctl 将需要监视的 socket 添加到epfd中 epoll 的事件注册函数,一次性将所有需要监听的socket加入到内核中,后续可以避免再次复制的开销
  • 最后调用 epoll_wait 等待数据。 等待事件的产生,收集在 epoll 监控的事件中已经发送的事件,类似于 select() 调用。

Epoll 的优点

  • epoll 在内核里使用红黑树来跟踪进程所有待检测的文件描述字,把需要监控的 socket 通过 epoll_ctl() 函数加入内核中的红黑树里,红黑树是个高效的数据结构,增删改一般时间复杂度是 O(logn)减少了内核和用户空间大量的数据拷贝和内存分配。
  • epoll 使用事件驱动的机制,内核里维护了一个链表来记录就绪事件,当某个 socket 有事件发生时,通过回调函数内核会将其加入到这个就绪事件列表中,当用户调用 epoll_wait() 函数时,只会返回有事件发生的文件描述符的个数,不需要像 select/poll 那样轮询扫描整个 socket 集合,大大提高了检测的效率。

Epoll 边缘触发和水平触发

使用边缘触发模式时,当被监控的 Socket 描述符上有可读事件发生时,服务器端只会从 epoll_wait 中苏醒一次,即使进程没有调用 read 函数从内核读取数据,也依然只苏醒一次,因此我们程序要保证一次性将内核缓冲区的数据读取完;

使用水平触发模式时,当被监控的 Socket 上有可读事件发生时,服务器端不断地从 epoll_wait 中苏醒,直到内核缓冲区数据被 read 函数读完才结束,目的是告诉我们有数据需要读取;

举个例子,你的快递被放到了一个快递箱里,如果快递箱只会通过短信通知你一次,即使你一直没有去取,它也不会再发送第二条短信提醒你,这个方式就是边缘触发;如果快递箱发现你的快递没有被取出,它就会不停地发短信通知你,直到你取出了快递,它才消停,这个就是水平触发的方式。

  • 边缘触发:数据没处理完后续不会再触发事件
  • 水平触发:是不管数据有没有触发都返回事件

一般来说,边缘触发的效率比水平触发的效率要高,因为边缘触发可以减少 epoll_wait 的系统调用次数,系统调用也是有一定的开销的的,毕竟也存在上下文的切换。

小结

  • select: select允许程序同时监控多个文件描述符的读写状态,但受限于位图大小,且每次调用都需从用户空间向内核空间复制位图,性能开销大。
  • poll: poll改进了select,使用数组存储文件描述符,无位图大小限制,可处理更多文件描述符。但同样存在每次调用时的用户空间到内核空间的复制开销。
  • epoll: epoll是Linux特有的高效IO多路复用机制,基于事件驱动,无需轮询,通过注册感兴趣的事件并在事件发生时通知应用程序,适合处理大量并发连接,性能优越且资源消耗低。


相关文章
|
2天前
|
存储 监控 Linux
【Linux IO多路复用 】 Linux下select函数全解析:驾驭I-O复用的高效之道
【Linux IO多路复用 】 Linux下select函数全解析:驾驭I-O复用的高效之道
68 0
|
2天前
|
存储 Linux 调度
io复用之epoll核心源码剖析
epoll底层实现中有两个关键的数据结构,一个是eventpoll另一个是epitem,其中eventpoll中有两个成员变量分别是rbr和rdlist,前者指向一颗红黑树的根,后者指向双向链表的头。而epitem则是红黑树节点和双向链表节点的综合体,也就是说epitem即可作为树的节点,又可以作为链表的节点,并且epitem中包含着用户注册的事件。当用户调用epoll_create()时,会创建eventpoll对象(包含一个红黑树和一个双链表);
74 0
io复用之epoll核心源码剖析
|
2天前
|
存储 网络协议
TCP服务器 IO多路复用的实现:select、poll、epoll
TCP服务器 IO多路复用的实现:select、poll、epoll
37 0
|
2天前
|
缓存 网络协议 Unix
Linux(UNIX)五种网络I/O模型与IO多路复用
Linux(UNIX)五种网络I/O模型与IO多路复用
115 0
|
2天前
|
网络协议 Linux C++
Linux C/C++ 开发(学习笔记十二 ):TCP服务器(并发网络编程io多路复用epoll)
Linux C/C++ 开发(学习笔记十二 ):TCP服务器(并发网络编程io多路复用epoll)
62 0
|
2天前
|
存储 Linux
图解IO多路复用模型之select、poll、epoll
图解IO多路复用模型之select、poll、epoll
58 0
|
2天前
|
NoSQL Java Linux
【Linux IO多路复用 】 Linux 网络编程 认知负荷与Epoll:高性能I-O多路复用的实现与优化
【Linux IO多路复用 】 Linux 网络编程 认知负荷与Epoll:高性能I-O多路复用的实现与优化
73 0
|
2天前
|
JavaScript Unix Linux
IO多路复用:提高网络应用性能的利器
IO多路复用:提高网络应用性能的利器
|
2天前
|
网络协议 架构师 Linux
一文说透IO多路复用select/poll/epoll
一文说透IO多路复用select/poll/epoll
174 0
|
2天前
|
网络协议 Linux
2.1.1网络io与io多路复用select/poll/epoll
2.1.1网络io与io多路复用select/poll/epoll

热门文章

最新文章