什么是IO多路复用?
先理解名字:
IO多路复用=多个IO连接复用同一个线程
定义
IO多路复用是一种同步IO模型,实现一个线程监视多个文件描述符fd;一旦某个文件描述符fd就绪,就能够通知应用程序进行相应的读写操作;没有fd就绪时会阻塞应用程序,交出cpu
上面的这句定义未免有些抽象,我们来尝试理解一下
理解IO多路复用原理:
-
我们拿到了一堆
文件描述符fd
(网络相关、磁盘文件相关等等,任何文件描述符都可以) -
通过调用某个函数告诉内核:“这个函数你先不要返回,你替我监视着这些描述符,当这堆文件描述符中有可以进行I/O读写操作的时候你再返回告诉我”
-
当调用的这个函数返回后,我们就能知道
哪些文件描述符
可以进行I/O操作了。
图示
IO多路复用特点
1、与多线程技术相比
I/O多路复用技术的最大优势
是系统开销小
,因为IO多路复用不必创建多个线程,也不必维护这些线程,从而大大减小了系统的开销。
2、与阻塞式I/O的对比
两种模式的两个阶段都阻塞,那区别在哪里呢?
虽然第一阶段都是阻塞,但是阻塞式I/O如果要接收更多的连接,就必须创建更多的线程。
而I/O复用模式下只要单个线程
处理这些连接事件就可以了,一旦达到“就绪”
的条件,就可以立即执行真正的I/O操作。
这就是I/O复用与传统的阻塞式I/O最大的不同。也正是I/O复用的精髓所在。
3、IO多路复用是同步阻塞IO
因为用户进程在等待数据
和拷贝数据
这两个阶段都是阻塞的。
实现IO多路复用的三种机制
在Linux世界中有这样三种机制可以用来进行I/O多路复用
select
poll
epoll
select
在select这种I/O多路复用机制下,我们需要把想监控的fd集合
通过函数参数
的形式告诉select,然后select会将这些fd集合
拷贝到内核
中,然后遍历所有fd
找到就绪fd
返回给应用程序。
select三个缺点:
-
规定监控的fd集合
不能超过1024个
因为数据拷贝是有性能损耗的,当线程监控的fd过多会导致拷贝数据的时间过多,从而使得性能变慢。 -
每次调用select,都需要把
所有的fd集合
从用户态拷贝
到内核态,fd越多开销则越大; -
每次调用select都需要在内核
遍历所有fd
来找到具体是哪个文件描述符已就绪,这个开销在fd很多时也很大。
poll
poll是基于链表来存储的,所以poll没有最大连接数的限制
但是另外两个缺点没有解决
epoll
Epoll只关心就绪的连接,不关心连接总数,因此在实际的网络环境中,Epoll的效率就会远远高于select和poll
Epoll的优点
-
文件描述符
数量不再受限
(1G的内存上能监听约10万
个端口);解决缺点1 -
使用
内存映射mmap
技术,节省了用户态和内核态间数据拷贝
的资源消耗;解决缺点2 -
不再遍历所有fd
,只有就绪的fd才会执行回调函数。I/O的效率不会随着监视fd的数量的增长而下降;解决缺点3
三种模式如何选择
表面上看epoll的性能最好,但是在连接数少
并且连接都十分活跃
的情况下,select和poll的性能可能比epoll好
但是当并发连接(fd)
较多时,Epoll的优势便真正展现出来。