select和epoll的区别(面试常考)
- 首先select是posix支持的,而epoll是linux特定的系统调用,因此,epoll的可移植性就没有select好,但是考虑到epoll和select一般用作服务器的比较多,而服务器中大多又是linux,所以这个可移植性的影响应该不会很大。
- 其次,select可以监听的文件描述符有限,最大值为1024,而epoll可以监听的文件描述符则是系统对整个进程限制的最大文件描述符。
- 接下来就要谈epoll和select的性能比较了,这个一般情况下应该是epoll表现好一些,否则linux也不会去特定实现epoll函数了,那么epoll为什么比select更高效呢?原因如下:
- 第一点,epoll通过每次有就绪事件时都将其插入到一个就绪队列中,使得epoll_wait的返回结果中只存储了已经就绪的事件,而select则返回了所有被监听的事件,事件是否就绪需要应用程序去检测,那么如果已被监听但未就绪的事件较多的话,对性能的影响就比较大了。
- 第二点,每一次调用select 获得就绪事件时都要将需要监听的事件重复传递给操作系统内核,而epoll获得就绪事件和设置监听事件是分开,这样获得就绪事件的调用epoll_wait就不需要重新传递需要监听的事件列表,这种重复的传递需要监听的事件也是性能低下的原因之一。
- 除此之外,epoll在内核维护一个事件表,并提供了一个独立的系统调用epoll_ctl来控制添加、删除、修改事件,这样,epoll_wait每次都是直接从该内核事件表中获取用户注册的事件,无需反复从用户空间读入这些事件。
- 然后就是epoll提供了两种工作模式,一种是水平触发模式,这种模式和select的触发方式是一样的,要只要文件描述符的缓冲区中有数据,就永远通知用户这个描述符是可读的,这种模式对block和noblock的描述符都支持,编程的难度也比较小;而另一种更高效且只有epoll提供的模式是边缘触发模式,只支持nonblock的文件描述符,他只有在文件描述符有新的监听事件发生的时候(例如有新的数据包到达)才会通知应用程序,在没有新的监听事件发生时,即使缓冲区有数据(即上一次没有读完,或者甚至没有读),epoll也不会继续通知应用程序,使用这种模式一般要求应用程序收到文件描述符读就绪通知时,要一直循环读数据直到收到EWOULDBLOCK/EAGAIN错误(循环读,所以需要非阻塞,否则会死等),使用边缘触发就必须要将缓冲区中的内容读完,否则有可能引起死等。另外,如果对listen_fd使用ET模式监听到达连接的时候,这时如果有多个连接同时到达,如果每次只是调用accept一次,就会导致多个连接在内核缓冲区中滞留,处理的办法是用while循环抱住accept,直到其出现EAGAIN。这种模式虽然容易编程出错,但是性能要比前面的模式更高效,因为只需要监听是否有事件发生,发生了就直接将描述符加入就绪队列即可。
epoll的使用场景
- epoll的高性能, 是有一定的特定场景的. 如果场景选择的不适宜, epoll的性能可能适得其反。
- 对于多连接, 且多连接中只有一部分连接比较活跃时, 比较适合使用epoll。
例如, 典型的一个需要处理上万个客户端的服务器, 例如各种互联网APP的入口服务器, 这样的服务器就很适合epoll.如果只是系统内部, 服务器和服务器之间进行通信, 只有少数的几个连接, 这种情况下用epoll就并不合适. 具体要根据需求和场景特点来决定使用哪种IO模型。
总结
select和epoll区别:文章来源:https://www.toymoban.com/news/detail-428129.html
- 可扩展性不同:select更好
- select可以监听的文件描述符有限,大概是1024,而epoll可以支持系统给整个进程的限制的最大文件描述符数量
- 性能不同:有三个点
- epoll_wait只会返回已经准备就绪的事件,而select会返回所有的事件,需要用户自己查找哪些事件准备就绪,如果已监听,而未就绪的事件过多,会影响性能
- select获取返回事件时都需要把需要监听的文件描述符重复传给内核,而epoll监听和获取事件是分开的
- epoll在内核维护了一个事件表,linux还专门提供了一个系统调用支持epoll_ctl来完成对事件的增删改,因此epoll_wait每次都是直接从内核事件表中获取用户注册事件。
水平触发与边缘触发:文章来源地址https://www.toymoban.com/news/detail-428129.html
- 水平触发:和select一样的模式,编程难度低,一旦文件描述符缓冲区有数据,就会通知进程,支持阻塞和非阻塞的文件描述符
- 边缘触发:只有文件描述符缓冲区有新的数据到达时,才会通知。如果当前在读文件描述符的缓冲区的数据没有读完,在下一次循环不会再通知。所以需要使用while循环来读,直到缓冲区数据读完,所以仅支持非阻塞的文件描述符,不然会导致死等。
到了这里,关于epoll与select区别的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!