什么是多路复用
IO 多路复用中多路是指网络连接,复用指的是同一个线程,可以理解为一个线程管理多个连接,是一种同步IO模型,实现一个线程可以监视多个文件句柄;一旦某个文件句柄就绪,就能够通知应用程序进行相应的读写操作;没有文件句柄就绪就会阻塞应用程序,交出CPU。这种机制的使用需要额外的功能来配合: select、poll、epoll。
为什么需要多路复用
多路复用还是提高效率,节省时间,怎么节约时间呢?在多路复用之前,我们看下网络模型是怎么样的?基于这张神图:
这是阻塞IO 模型(Blocking IO ),应用跟操作系统交互 请求读取数据,这个时候操作系统要开始读取数据,一直到数据先加载到kernel buff中,然后从kernel复制到user空间,这样应用系统就读取到了。这全程都是一个线程处理,并且应用也一直在等待,那如果一个应用要读取多个数据呢?那就一个一个排队,不是并发的操作。
那肯定就有人说了,能不能快点?能不能不阻塞,于是就有了Non-Blocking IO ,看看图:
这里就是应用不停的去请求内核,数据准备好了没,不停的请求,数据准备好了就return OK,这样不会被阻塞,但会不停的请求,消耗cpu。那就有没有系统来通知我数据准备好了,这样我就不需要每次请求内核,于是就有了多路复用(IO Multiplexing ),看看图:
这样就可以不用每次都请求数据了,但要请求2次才能拿到数据,不过另一个好处就是可以多次select请求,然后那个请求数据好了,就recvfrom 处理数据,不过这里可以看到第一个wait for data 是非阻塞的,不用占用应用,但第二个 copy 到 user 是需要阻塞的,总体来说虽然没有节约系统准备数据的时间,但多路复用可以复用一个线程来发送select请求,多个线程来处理已经就绪的数据,将请求和接受数据形成两个操作,并且解耦。附属上总的IO模型的概念图:
多路复用机制
多路复用的实现主要是利用单线程采用select\poll\epoll等等系统调用获取 fd 列表,遍历有事件的 fd 进行 accept/recv/send ,使其能支持更多的并发连接请求。其中select、poll,epoll本质上都是同步I/O,因为他们都需要在读写事件就绪后自己负责进行读写FD,读写过程是阻塞的,这三种方法区别获取fd的方式上。
前提知识:文件描述符FD
文件描述符(File descriptor)是计算机科学中的一个术语,是一个用于表述指向文件的引用的抽象化概念。文件描述符在形式上是一个非负整数。实际上,它是一个索引值,指向内核为每一个进程所维护的该进程打开文件的记录表。当程序打开一个现有文件或者创建一个新文件时,内核向进程返回一个文件描述符。在程序设计中,一些涉及底层的程序编写往往会围绕着文件描述符展开。但是文件描述符这一概念往往只适用于UNIX、Linux这样的操作系统。
select缺点
select本质上是通过设置或者检查存放fd标志位的数据结构来进行下一步处理。这样所带来的缺点是:
-
单个进程所打开的FD是有限制的,通过 FD_SETSIZE 设置,默认1024 ;
-
每次调用 select,都需要把 fd 集合从用户态拷贝到内核态,这个开销在 fd 很多时会很大;
需要维护一个用来存放大量fd的数据结构,这样会使得用户空间和内核空间在传递该结构时复制开销大 -
对 socket 扫描时是线性扫描,采用轮询的方法,效率较低(高并发)
当套接字比较多的时候,每次select()都要通过遍历FD_SETSIZE个Socket来完成调度,不管哪个Socket是活跃的,都遍历一遍。这会浪费很多CPU时间。如果能给套接字注册某个回调函数,当他们活跃时,自动完成相关操作,那就避免了轮询,这正是epoll与kqueue做的。
poll缺点
poll本质上和select没有区别,它将用户传入的数组拷贝到内核空间,然后查询每个fd对应的设备状态, 但是它没有最大连接数的限制,原因是它是基于链表来存储的,它没有最大连接数的限制,原因是它是基于链表来存储的,但是同样有缺点:
- 每次调用 poll ,都需要把 fd 集合从用户态拷贝到内核态,这个开销在 fd 很多时会很大;
- 对 socket 扫描是线性扫描,采用轮询的方法,效率较低(高并发时)
epoll缺点
epoll可以理解为event poll,不同于忙轮询和无差别轮询,epoll会把哪个流发生了怎样的I/O事件通知我们。所以我们说epoll实际上是**事件驱动(每个事件关联上fd)的,此时我们对这些流的操作都是有意义的。
epoll的优点:
- 没有最大并发连接的限制,能打开的FD的上限远大于1024(1G的内存上能监听约10万个端口);
效率提升,不是轮询的方式,不会随着FD数目的增加效率下降。只有活跃可用的FD才会调用callback函数;即- Epoll最大的优点就在于它只管你“活跃”的连接,而跟连接总数无关,因此在实际的网络环境中,Epoll的效率就会远远高于select和poll; - 内存拷贝,利用mmap()文件映射内存加速与内核空间的消息传递;即epoll使用mmap减少复制开销。
epoll缺点:
- epoll只能工作在 linux 下
参考博客
彻底理解 IO 多路复用实现机制
Linux 网络编程的5种IO模型:多路复用(select/poll/epoll)
知乎:怎么理解多路复用