Nginx源代码分析之I/O模型(六)

Windows 有5大I/O模型,unix则有 select,poll,epoll,kqueue等等

先看看linux平台,早期使用最多的是select,poll。2者的原理类似,将监听的所有描述符加入到描述符的读写集合里面。

然后循环调用select/poll,每次调用select,都只重复执行以下操作:

使用copy_from_user从用户空间拷贝fd_set到内核空间,遍历所有fd,调用其对应的poll方法,把当前进程挂到设备的等待队列中,在设备收到一条的数据后,会唤醒设备等待队列上睡眠的进程,这时当前线程便被唤醒了,poll方法返回时会返回一个描述读写操作是否就绪的mask掩码,根据这个mask掩码给fd_set赋值,最后再把fd_set从内核空间拷贝到用户空间。

可以参考下图:


可以看到每次调用select都有很大的开销,发生2次内核与应用层之间的所有描述符拷贝,一次对所有fd的遍历,因此select,poll的效率都很低。

而epoll改进了对描述符的监听和控制方法,其本质是,不再每次调用select去遍历所有fd,而是在内核中把有数据的fd加入一个就绪表中,应用层做的仅仅是不断从这个就绪表获取就绪的FD,然后读取里面的数据,这样省却应用层的很多多余操作,效率也就大大的提高了。


再详细分析一下,epoll提供了三个函数,epoll_create,epoll_ctl和epoll_wait,epoll_create是创建一个epoll句柄;epoll_ctl是注册要监听的事件类型;epoll_wait则是等待事件的产生。按Linux的规定,epoll_create指定了epoll监听的最大描述符的数量。然后根据这个最大限制,一般会创建一个epoll_event的结构数组,epoll_ctl做的事情是把新的epoll_event加入指定的epoll对象的监控表中,此表位于内核空间中。而前面说了,这个表的大小在epoll_create的时候指定,因此,这个表其实是在epoll_create的时候就创建了,调用epoll_ctl只是把新的fd写入表中或者从表中删除,同时,会把当前进程挂到这个fd设备等待列表上,并为每个fd指定一个回调函数,当设备就绪,唤醒等待队列上的等待者时,就会调用这个回调函数,而这个回调函数会把就绪的fd加入就绪链表。


现在epoll_wait被调用,需把初始化创建的epoll_event数组传递进去。epoll_wait会将内核就绪列表中的fd拷贝到此数组中,并返回就绪fd的总数。

大致如下图说示




再看看windows平台,纯粹为了兼容的win32 select暂且不提,且看看用途广泛的重叠模型,与select一样.重叠模型会创建一个与I/O关联的事件对象的集合,并反复调用WaitForMultipleObjects监听所有事件的状态,一样的涉及到对所有事件的遍历,以及内核和应用层之间的切换,效率较低。



再看看OCP模型,IOCP会创建一个完成端口对象,与重叠模型不同的是,IOCP不会调用WaitForMultipleObjects去轮询所有与I/O关联的事件对象,他甚至已经摈弃掉对事件通知的依赖,而是将数个线程与IOCP对象直接关联,在这些线程中通过调用GetQueuedCompletionStatus来直接获取已经完成的I/O,并调用WSAGetOverlappedResult来直接返回单次I/O的数据。因此iocp跟epoll一样是把就绪的I/O放在一个制定的队列中,然后返回给应用层,而且iocp是天然多线程的,CompletionPort可供多个线程同时调用GetQueuedCompletionStatus,在系统内部,该方法能很好的让多个线程的负载均衡分配。可以参考下图:




因此iocp是与epoll比较类似的一个网络I/O模型,但二者也有明显的差别

一,对于多线程,ET模式是不支持多线程的,如果想实现多个线程对epoll描述符调用eoll_wait,还需要一些特殊设置,否则可能会导致不同的线程获取到同一个就绪的socket。IOCP对多线程有良好的支持,并且实际上是附带了线程池的功能。另外微软还提供了系统线程池组件,把线程池和IOCP直接封装在一起,这些特性使IOCP在多核系统中有非常高的性能。


二,epoll只会执行事件通知,而不会直接复制I/O的数据,读写数据的操作应该由调用者收到就绪通知后,自行调用相应的I/O函数来实现。而iocp则在内核中完成了I/O的读写,当应用层收到I/O完成的通知之后,I/O数据已经复制到用户的内存中,这应该是iocp比epoll高效的一个地方。


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值