Skip to content

IO多路复用

一、概念

I/O多路复用,I/O指的是网络I/O,多路值多个TCP连接(socket或者channel),复用指复用一个或者几个线程;

简单来说:就是使用一个或几个线程处理多个TCP连接

最大的优势是减少系统的开销,不必创建过多的进程/线程,也不必维护这些进程/线程。

二、select

基本原理:

监视文件三类描述符:writefds,readfds和exceptfds。

调用select函数会堵塞住,等有数据 可读、可写、出异常或者超时就会返回

select函数正常返回后,通过遍历fdset整个数组才能发现哪些句柄发生了事件,来找到就绪的描述符fd,然后进行对应的IO操作。

几乎在所有的平台支持,跨平台特性好。

缺点:

  1. select采用轮询的方式扫描文件描述符,全部扫描,随着文件描述符FD数量增多而性能下降

  2. 每次调用select()需要把fd集合从用户态拷贝到内核态,并进行遍历(消息传递都是从内核到用户空间)

  3. 最大的缺陷就是单个进程打开的FD有限制,默认是1024(可修改宏定义,但是效率仍然慢)

三、poll

select和poll系统调用是一样的,处理多个描述符也是使用轮询的方式,根据描述符的状态进行处理一样需要把fd集合从用户态拷贝到内存态,并进行遍历。

最大的区别:poll没有最大文件描述符限制(使用链表方式存储的fd)

四、epoll

在2.6内核中提出,对比select和poll,epoll更加灵活,没有描述符限制,用户态拷贝到内核态只需要一次使用通知事件,通过epoll_etl注册fd,一旦fd就绪,内核就会采用callback的回调机制来激活对应的fd。

优点:

  1. 没有fd的限制,所支持的fd上限是操作系统的最大文件句柄数,1G内存大概支持10万句柄。

  2. 效率提高,使用回调通知,而不是使用轮询的方式,不会随着fd数目的增加而效率下降。

  3. 通过callback机制通知,内核和用户空间mmap同一块内存实现

缺点:

编程模型比select/poll复杂

linux内核函数实现:

  1. epoll_create() 在linux内核申请一个文件系统,B+树结构,返回这个epoll对象,是一个fd。

  2. epoll_etl() 操作epoll对象,在这个对象里面添加删除修改对应的链接fd,绑定一个callback函数

  3. epoll_wait() 判断并完成对应的IO操作