Linux IO 多路复用
简介
linux io 多路复用是用来实现单进程同时处理多个io请求的有效方法。
linux的io多路复用主要有以下3中方式:
select
poll
epoll
select
select函数监视的文件描述符有三类,readfds,writefds,exceptfds。调用后函数会阻塞,直到有描述符就绪(有数据读、写、或者有except),或者超时(timeout指定时间,如果立即返回设置null),函数返回。当select函数返回后,可以通过便利fdset,
|
|
select 实现方式:
用户进程将要监听的
fd
放到一个文件描述符集合fd_set
中,该fd_se
t是一个BitsMap,一次最多可监听1024个fd;用户进程调用
select()
函数将fd_set
拷贝到内核;内核遍历各
fd_set
,检查是否有网络事件产生;内核当检查到有事件产生后,将此
fd
标记为可读或可写;内核把
fd_set
拷贝回用户态里;用户进程遍历
fd_set
, 找到可读或可写的fd
,然后再对其处理。
select:效率低,性能不太好。不能解决大量并发请求的问题。
poll
|
|
- poll基本原理和selec相同;
- 不同之处在于:不用 BitsMap而是链表来存储
fd_set
, 因此一次监听的fd
数量不会受到bitsmap的限制;
epoll
epoll_create: 创建epoll池子。
epoll_ctl:向epoll注册事件。告诉内核epoll关心哪些文件,让内核没有健忘症。
epoll_wait:等待就绪事件的到来。专门等哪些文件,第2个参数 是输出参数,包含满足的fd,不需要再遍历所有的fd文件。
|
|
ET和LT
epoll 支持两种事件触发模式,分别是边缘触发(edge-triggered,ET)和水平触发(level-triggered,LT)。
- 使用边缘触发模式(EdgeTriger)时,当被监控的 Socket 描述符上有可读事件发生时,服务器端只会从 epoll_wait 中苏醒一次,即使进程没有调用 read 函数从内核读取数据,也依然只苏醒一次,因此我们程序要保证一次性将内核缓冲区的数据读取完;
- 使用水平触发模式时,当被监控的 Socket 上有可读事件发生时,服务器端不断地从 epoll_wait 中苏醒,直到内核缓冲区数据被 read 函数读完才结束,目的是告诉我们有数据需要读取;
signal IO
目前在linux中很少被用到,Linux内核某个IO事件ready,通过kill出一个signal,应用程序在signal IO上绑定处理函数。
kernel发现设备读写事件变化,调用一个 kill fa_sync ,应用程序绑定signal_io上的事件。