前言:关于并发服务器中的I/O复用实现方式,前面我们讲过select的方式,但select的性能比较低,其实不合适以Web服务器端开发为主流的现代开发环境。因此就有了Linux下的epoll,BSD的kqueue,Solaris的/dev/poll和Windows的IOCP等复用技术。本章就来说讲Linux下的epoll技术。
基于select的I/O复用技术速度慢的缘由:
1,调用select函数后常见的针对所有文件描写符的循环语句。它每次事件产生需要遍历所有文件描写符,找动身生变化的文件描写符。(之前写的示例没加循环)
2,每次调用select函数时都需要向该函数传递监视对象信息。即每次调用select函数时向操作系统传递监视对象信息,至于为何要传?是由于我们监视的套接字变化的函数,而套接字是操作系统管理的。(这个才是最耗效力的)
注释:基于这样的缘由其实不是说select就没用了,在这样的情况下就合适选用select:1,服务端接入者少 2,程序应具有兼容性。
epoll是怎样优化select问题的:
1,每次产生事件它不需要循环遍历所有文件描写符,它把产生变化的文件描写符单独集中到了1起。
2,仅向操作系统传递1次监视对象信息,监视范围或内容产生变化时只通知产生变化的事项。
实现epoll时必要的函数和结构体
函数:
epoll_create:创建保存epoll文件描写符的空间,该函数也会返回文件描写符,所以终止时,也要调用close函数。(创建内存空间)epoll_ctl:向空间注册,添加或修改文件描写符。(注册监听事件)
epoll_wait:与select函数类似,等待文件描写符产生变化。(监听事件回调)
结构体:
struct epoll_event
{
__uint32_t events;
epoll_data_t data;
}typedef union epoll_data
{
void *ptr;
int fd;
__uinit32_t u32;
__uint64_t u64;
} epoll_data_t;
甚么是条件触发和边沿触发?它们是指事件响应的方式,epoll默许是条件触发的方式。条件触发是指:只要输入缓冲中有数据就会1直通知该事件,循环响应epoll_wait。而边沿触发是指:输入缓冲收到数据时仅注册1次该事件,即便输入缓冲中还留有数据,也不会再进行注册,只响应1次。
边沿触发相对条件触发的优点:可以分离接收数据和处理数据的时间点,从实现模型的角度看,边沿触发更有可能带来高性能。
将上面epoll实例改成边沿触发:
1,首先改写 event.events = EPOLLIN | EPOLLET; (EPOLLIN:读取数据事件 EPOLLET:边沿触发方式)
2,边沿触发只响应1次接收数据事件,所以要1次性全部读取输入缓冲中的数据,那末就需要判断甚么时候数据读取完了?Linux声明了1个全局的变量:int errno; (error.h中),它能记录产生毛病时提供额外的信息。这里就能够用它来判断是不是读取完数据:
3,边沿触发方式下,以阻塞方式工作的read&write有可能会引发服务真个长时间停顿。所以边沿触发1定要采取非阻塞的套接字数据传输情势。那末怎样将套接字的read,write数据传输情势修改成非阻塞模式呢?
上一篇 代码天敌之体积计算