从I/O复用谈epoll为什么高效

上一篇文章中,谈了一些网络编程的基本概念。在现实使用中,用的最多的就是I/O复用了,无非就是select,poll,epoll

很多人提到网络就说epoll,认为epoll效率是最高的。单纯的这么认为,其实有失偏颇。epoll固然高效,可是它是怎么做到高效的,它到底比select或poll优异在哪儿?

我们通过调用流程来简单分析下。

首先以select为例(poll类似),看下其调用过程

1.选择想要处理的套接字,通过接口FD_SET(fd, &set)加入到set中;

2.调用select(max+1, &set,,..)

3.对set中所有套接字调用FD_ISSET(fd,&set),查看fd上是否有事件发生

select存在的问题

  1. 单个进程能够监视的文件描述符的数量存在最大限制,通常是1024,当然可以更改数量,但由于select采用轮询的方式扫描文件描述符,文件描述符数量越多,性能越差;(在linux内核头文件中,有这样的定义:#define __FD_SETSIZE    1024)
  2. 内核 / 用户空间内存拷贝问题,select需要复制大量的句柄数据结构,产生巨大的开销;
  3. select返回的是含有整个句柄的数组,应用程序需要遍历整个数组才能发现哪些句柄发生了事件;
  4. select的触发方式是水平触发,应用程序如果没有完成对一个已经就绪的文件描述符进行IO操作,那么之后每次select调用还是会将这些文件描述符通知进程。

epoll调用过程

1 .epoll_create 创建一个epoll对象,一般epollfd = epoll_create()

2 .epoll_ctl (epoll_add/epoll_del的合体),往epoll对象中增加/删除某一个流的某一个事件

比如epoll_ctl(epollfd, EPOLL_CTL_ADD, socket, EPOLLIN);//注册缓冲区非空事件,即有数据流入

epoll_ctl(epollfd, EPOLL_CTL_DEL, socket, EPOLLOUT);//注册缓冲区非满事件,即流可以被写入

添加事件的时候,其实是向内核注册了一个回调函数。回调函数作用是,在相应的套接字上发生事件时,将其加入到epoll对象的时间就绪链表中,而这是在内核完成的。

3 epoll_wait(epollfd,...),获取就绪事件。即从就绪事件链表中取出所有的事件。

可以看到epoll比select高效的地方在于,其返回的就是所有已经发生事件的套接字,而不需要像select那样需要在用户态去判断每个套接字上是否有事件发生。

另外,在调用select时,内核需要去一一检测传入的套接字集合是否有事件,而调用epoll_wait时,只是将内核中的就绪数据取出而已

如果有n个连接,并且这n个连接都有事件发生,那么使用select与epoll其实并没有多少区别。对于select来说,用户态对每一个套接字的事件监测都是有效的。

但是select有一个问题是,每次去调用select之前,都要重置套接字set。如果连接数很大,每次FD_SET(fd, &set)调用接口,也会对性能造成不小的影响。而epoll中,只需调用一次epoll_ctl即可。

所以,在连接数很大,且活跃连接不多的情况下,使用epoll有明显的优势;而如果连接数较少,且连接基本都是活跃的,其实select的效果反而会更好。

时间: 2025-01-16 08:26:28

从I/O复用谈epoll为什么高效的相关文章

Linux下的I/O复用与epoll详解

前言 I/O多路复用有很多种实现.在linux上,2.4内核前主要是select和poll,自Linux 2.6内核正式引入epoll以来,epoll已经成为了目前实现高性能网络服务器的必备技术.尽管他们的使用方法不尽相同,但是本质上却没有什么区别.本文将重点探讨将放在EPOLL的实现与使用详解. 为什么会是EPOLL select的缺陷 高并发的核心解决方案是1个线程处理所有连接的“等待消息准备好”,这一点上epoll和select是无争议的.但select预估错误了一件事,当数十万并发连接存

从select的一个死循环谈epoll的ET模式

--作者:lvyilong316 最近写程序遇到一个问题,就是发现select监听标准输出的时候遇到了死循环,具体程序如下程序一.程序的意图是每当用户在控制台有任何输入,就输出"hello world!". 程序一: #include <stdio.h> #include <sys/types.h> #include <unistd.h> #include <sys/select.h> int main(int argc, char *a

linux下的epoll如何高效处理百万连接

开发高性能网络程序时,windows开发者们言必称iocp,linux开发者们则言必称epoll.大家都明白epoll是一种IO多路复用技术,可以非常高效的处理数以百万计的socket句柄,比起以前的select和poll效率高大发了.我们用起epoll来都感觉挺爽,确实快,那么,它到底为什么可以高速处理这么多并发连接呢? 先简单回顾下如何使用C库封装的3个epoll系统调用吧. [cpp] view plaincopy int epoll_create(int size); int epoll

linux下的epoll怎样高效处理百万连接

开发高性能网络程序时.windows开发人员们言必称iocp,linux开发人员们则言必称epoll.大家都明确epoll是一种IO多路复用技术,能够很高效的处理数以百万计的socket句柄,比起曾经的select和poll效率高大发了. 我们用起epoll来都感觉挺爽,确实快,那么.它究竟为什么能够快速处理这么多并发连接呢? 先简单回想下怎样使用C库封装的3个epoll系统调用吧. [cpp] view plaincopy int epoll_create(int size); int epo

IO复用之——epoll

一. 关于epoll 对于IO复用模型,前面谈论过了关于select和poll函数的使用,select提供给用户一个关于存储事件的数据结构fd_set来统一监测等待事件的就绪,分为读.写和异常事件集:而poll则是用一个个的pollfd类型的结构体管理事件的文件描述符和事件所关心的events,并通过结构体里面的输出型参数revents来通知用户事件的就绪状态: 但是对于上述两种函数,都是需要用户遍历所有的事件集合来确定到底是哪一个或者是哪些事件已经就绪可以进行数据的处理了,因此当要处理等待的事

多线程 or I/O复用select/epoll

1:多线程模型适用于处理短连接,且连接的打开关闭非常频繁的情形,但不适合处理长连接.线程模型默认情况下,在Linux下每个线程会开8M的栈空间,在TCP长连接的情况下,以2000/分钟的请求为例,几乎可以假定有上万甚至十几万的并发连接,假定有10000个连接,开这么多个线程需要10000*8M=80G的内存空间!即使调整每个线程的栈空间,也很难满足更多的需求.甚至攻击者可以利用这一点发动DDoS,只要一个连接连上服务器什么也不做,就能吃掉服务器几M的内存,这不同于多进程模型,线程间内存无法共享,

Linux I/O复用中select poll epoll模型的介绍及其优缺点的比较

关于I/O多路复用: I/O多路复用(又被称为"事件驱动"),首先要理解的是,操作系统为你提供了一个功能,当你的某个socket可读或者可写的时候,它可以给你一个通知.这样当配合非阻塞的socket使用时,只有当系统通知我哪个描述符可读了,我才去执行read操作,可以保证每次read都能读到有效数据而不做纯返回-1和EAGAIN的无用功.写操作类似.操作系统的这个功能通过select/poll/epoll之类的系统调用来实现,这些函数都可以同时监视多个描述符的读写就绪状况,这样,**多

Linux I/O复用中select poll epoll模型的介绍及其优缺点的比較

关于I/O多路复用: I/O多路复用(又被称为"事件驱动"),首先要理解的是.操作系统为你提供了一个功能.当你的某个socket可读或者可写的时候.它能够给你一个通知.这样当配合非堵塞的socket使用时,仅仅有当系统通知我哪个描写叙述符可读了,我才去运行read操作.能够保证每次read都能读到有效数据而不做纯返回-1和EAGAIN的无用功.写操作相似.操作系统的这个功能通过select/poll/epoll之类的系统调用来实现.这些函数都能够同一时候监视多个描写叙述符的读写就绪状况

I/O复用-epoll模型

epoll函数 epoll函数的使用与select.poll上有很大的差异. epoll使用一组函数来完成任务,而不是单个函数. epoll把用户关心的文件描述符上的事件放在内核里的一个事件表中,从而无需每次都要重复传入文件描述符集或者事件集. epoll需要一个额外的文件描述符,来唯一标示内核中的这个事件表. epoll函数 #include <sys/epoll.h> int epoll_create(int size); //size并不起作用,只是给内核一个提示,告诉它事件表需要多大.