IO复用的原理?零拷⻉?三个函数? epoll 的 LT 和 ET 模式的理解。
IO复⽤是Linux中的IO模型之⼀,IO复⽤就是进程预先告诉内核需要监视的IO条件,使得内核⼀旦发现进程指定的⼀个或多个IO条件就绪,就通过进程进程处理,从⽽不会在单个IO上阻塞了。Linux中,提供了select、poll、epoll三种接⼝函数来实现IO复⽤。
Select
select的缺点:
① 单个进程能够监视的⽂件描述符的数量存在最⼤限制,通常是1024。由于select采⽤轮询的⽅式扫描⽂件描述符,⽂件描述符数量越多,性能越差; ② 内核/⽤户空间内存拷⻉问题,select需要⼤量句柄数据结构,产⽣巨⼤开销; ③ Select返回的是含有整个句柄的数组,应⽤程序需要遍历整个数组才能发现哪些句柄发⽣事件; ④ Select的触发⽅式是⽔平触发,应⽤程序如果没有完成对⼀个已经就绪的⽂件描述符进⾏IO操作,那么每次select调⽤还会将这些⽂件描述符通知进程。
Poll 与select相⽐,poll使⽤链表保存⽂件描述符,⼀你才没有了监视⽂件数量的限制,但其他三个缺点依然存在
Epoll 上⾯所说的select缺点在epoll上不复存在,epoll使⽤⼀个⽂件描述符管理多个描述符,将⽤户关系的⽂件描述符的事件存放到内核的⼀个事件表中,这样在⽤户空间和内核空间的copy只需⼀次。Epoll是事件触发的,不是轮询查询的。没有最⼤的并发连接限制,内存拷⻉,利⽤mmap()⽂件映射内存加速与内核空间的消息传递。 区别总结:
⽀持⼀个进程所能打开的最⼤连接数 ① Select最⼤1024个连接,最⼤连接数有FD_SETSIZE宏定义,其⼤⼩是32位整数表示,可以改变宏定义进⾏修改,可以重新编译内核,性能可能会影响; ② Poll没有最⼤连接限制,原因是它是基于链表来存储的; ③ 连接数限数有上限,但是很⼤;
FD剧增后带来的IO效率问题 ① 因为每次进⾏线性遍历,所以随着FD的增加会造成遍历速度下降,效率降低; ② Poll同上; ③ 因为epool内核中实现是根据每个fd上的callback函数来实现的,只有活跃的socket才会主动调⽤callback,所以在活跃socket较少的情况下,使⽤epoll没有前⾯两者的现象下降的性能问题。
消息传递⽅式 ① Select内核需要将消息传递到⽤户空间,都需要内核拷⻉; ② Poll同上; ③ Epoll通过内核和⽤户空间共享来实现的。 epoll 的 LT 和 ET 模式的理解: epoll对⽂件描述符的操作有两种模式:LT(level trigger)和ET(edge trigger),LT是默认模式。 区别: LT模式:当epoll_wait检测到描述符事件发⽣并将此事件通知应⽤程序,应⽤程序可以不⽴即处理该事件。下次调⽤epoll_wait时,会再次响应应⽤程序并通知此事件。 ET模式:当epoll_wait检测到描述符事件发⽣并将此事件通知应⽤程序,应⽤程序必须⽴即处理该事件。如果不处理,下次调⽤epoll_wait时,不会再次响应应⽤程序并通知此事件。 在 select/poll中,进程只有在调⽤⼀定⽅法后,内核才对所有监视的⽂件描述符进⾏扫描,⽽epoll事先通过epoll_ctl()来注册⼀个⽂件描述符,⼀旦某个⽂件描述符就绪时,内核会采⽤类似callback的回调机制,迅速激活这个⽂件描述符,当进程调⽤epoll_wait时便得到通知(此处去掉了遍历⽂件描述符,⽽是通过监听回调的机制,这也是epoll的魅⼒所在)。Epoll 的优点主要体现如下⼏个⽅⾯:
监视的描述符不受限制,它所⽀持的FD上限是最⼤可以打开⽂件的数⽬,这个数字⼀般远⼤于2048,举个栗⼦,具体数⽬可以在cat/proc/sys/fs/file-max 查看,⼀般来说,这个数⽬和内存关系很⼤。
Select最⼤的缺点是进程打开的fd数⽬是有限制的,这对于连接数⽬较⼤的服务器来说根本不能满⾜,虽然也可以选择多进程的解决⽅案(Apache就是如此);不过虽然linux上⾯创建进程的代价较⼩,但仍旧不可忽视,加上进程间数据同步远⽐不上线程间同步⾼效,所以并不是⼀种完美的解决⽅案。
IO的效率不会随着监视fd的数量的增⻓⽽下降,epoll不同于select和poll的轮询⽅式,⽽是通过每个fd定义的回调函数来实现,只有就绪的fd才会执⾏回调函数。
如果没有⼤量的idle -connection或者dead-connection,epoll的效率并不会⽐select/poll⾼很多,但是当遇到⼤量的idle- connection,就会发现epoll的效率⼤⼤⾼于select/poll。
Last updated