关于EPoll的个人理解
1.epoll 是I/o多路复用的一种解决方案,对比select的优点有:
a.支持打开最大的文件描述符(可高达百万)
b.效率并不随着描述符的增多而线性下降。select每次是轮询,所以描述符越多效率越低。epoll的好处是利用事件触发,内核通过回调函数帮他(这是亲儿子)。
c.采用了mmap内存映射,减少内核区到用户区数据拷贝,又节省了不少时间。
2.Epoll又分为水平触发和边缘触发。
Level_triggered(水平触发):当被监控的文件描述符上有可读写事件发生时,epoll_wait()会通知处理程序去读写。如果这次没有把数据一次性全部读写完(如读写缓冲区太小),那么下次调用 epoll_wait()时,它还会通知你在上没读写完的文件描述符上继续读写,当然如果你一直不去读写,它会一直通知你!!!如果系统中有大量你不需要读写的就绪文件描述符,而它们每次都会返回,这样会大大降低处理程序检索自己关心的就绪文件描述符的效率!!!
Edge_triggered(边缘触发):当被监控的文件描述符上有可读写事件发生时,epoll_wait()会通知处理程序去读写。如果这次没有把数据全部读写完(如读写缓冲区太小),那么下次调用epoll_wait()时,它不会通知你,也就是它只会通知你一次,直到该文件描述符上出现第二次可读写事件才会通知你!!!这种模式比水平触发效率高,系统不会充斥大量你不关心的就绪文件描述符!!!
优缺点就很明显了,如过访问量过大,切每个事件的内容又很多的话,推荐边缘触发,因为每个事件的读取时要花长时间的,用边缘触发能明显减少事件的触发次数。
3.瓶颈。网上看的,不过倒是和我们的游戏服务器的限制想吻合。
单线程epoll,触发量可达到15000,但是加上业务后,因为大多数业务都与数据库打交道,所以就会存在阻塞的情况,这个时候就必须用多线程来提速。
代码实现:从服务端分析,什么时候该监听读,什么时候该监听写?(面试被问到过。。。)。从服务器的角度,客户端发送的请求都是需要读取的,所以是读事件,而服务器的返回数据是写事件。正常情况下应该是先读后写,有请求才返回嘛。写完之后这个描述符应该再切换回读事件,监听下次的请求。而且读是个被动事件,写是服务器的主动事件。所以网上大部分代码的实现都是默认监听读,服务器返回数据时将描述符置为写,写完后在还原读。
if(events[i].data.fd==listenfd) { connfd = accept(listenfd,(sockaddr *)&clientaddr, &clilen); if(connfd<0){ perror("connfd<0"); exit(1); } setnonblocking(connfd); char *str = inet_ntoa(clientaddr.sin_addr); //std::cout<<"connec_ from >>"< //设置用于读操作的文件描述符 ev.data.fd=connfd; //设置用于注测的读操作事件 ev.events=EPOLLIN|EPOLLET; //注册ev epoll_ctl(epfd,EPOLL_CTL_ADD,connfd,&ev); } else if(events[i].events&EPOLLIN) { //printf("reading!/n"); if ( (sockfd = events[i].data.fd) < 0) continue; new_task=new task(); new_task->fd=sockfd; new_task->next=NULL; //添加新的读任务 pthread_mutex_lock(&mutex); if(readhead==NULL) { readhead=new_task; readtail=new_task; } else { readtail->next=new_task; readtail=new_task; } //唤醒所有等待cond1条件的线程 pthread_cond_broadcast(&cond1); pthread_mutex_unlock(&mutex); } else if(events[i].events&EPOLLOUT) {
rdata=(struct user_data *)events[i].data.ptr;
sockfd = rdata->fd;
write(sockfd, rdata->line, rdata->n_size);
delete rdata;
//设置用于读操作的文件描述符
ev.data.fd=sockfd;
//设置用于注测的读操作事件
ev.events=EPOLLIN|EPOLLET;
//修改sockfd上要处理的事件为EPOLIN
epoll_ctl(epfd,EPOLL_CTL_MOD,sockfd,&ev);
}
posted on 2018-01-10 12:18 zyz913614263 阅读(215) 评论(0) 编辑 收藏 举报