转--select/poll/epoll到底是什么一回事
面试题:说说select/poll/epoll的区别。
这是面试后台开发时的高频面试题,属于网络编程和IO那一块的知识。Android里面的Handler消息处理机制的底层实现就用到了epoll。
为此,我在Google上看了很多相关文章,才大概搞懂是怎么一回事。
背景知识
文件描述符fd
文件描述符(File descriptor)是计算机科学中的一个术语,是一个用于表述指向文件的引用的抽象化概念。
文件描述符在形式上是一个非负整数。实际上,它是一个索引值,指向内核为每一个进程所维护的该进程打开文件的记录表。当程序打开一个现有文件或者创建一个新文件时,内核向进程返回一个文件描述符。在程序设计中,一些涉及底层的程序编写往往会围绕着文件描述符展开。但是文件描述符这一概念往往只适用于UNIX、Linux这样的操作系统。在Linux系统中,流在内核中可以表示成文件的形式。
IO模型
IO可以理解成对流的操作。
一般对于一个read操作发生时,它会经历两个阶段。
第一个阶段是等待数据准备。
第二个阶段是真正读取的过程,将数据从内核缓冲区拷贝到用户进程缓冲区中,
而五种常见的IO模型也是围绕这两个阶段来区分的。
同步模型(synchronous IO)
阻塞IO(bloking IO)
非阻塞IO(non-blocking IO)
多路复用IO(multiplexing IO)
信号驱动式IO(signal-driven IO)
异步IO(asynchronous IO)
其中,IO多路复用就是一种机制,实现一个进程可以监视多个描述符,一旦某个描述符就绪,就能够通知程序进行相应的读写操作。IO多路复用相比于多线程的优势在于系统的开销小,系统不必创建和维护进程或线程,免去了线程或进程的切换带来的开销。而操作系统支持IO多路复用的系统调用有select,poll和epoll。
select
先来看看select的函数声明:
int select (int n, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout);
1
fd_set是表示文件描述符集合的数据结构。readfds,writefds和exceptfds分别对应三类文件描述符集。当select被调用时,内部逻辑如下:
将3个fd集copy到内核,这里限制了fd最大数量为1024
线程阻塞,直到超时或内核检测到有fd可读或可写,内核会通知监控者select,select返回可读或可写的fd总数
那么用户进程如何找到可读可写的fd呢?select会将之前传递给内核的fd集从内核copy到用户进程。用户进程通过遍历的方式找到可读可写的fd。
缺点:
copy次数过多,而且每次调用select方法都要进行fd集的copy操作
select监控fd数量有限
用户进程通过遍历的方式找到可读写的fd,时间复杂度为o(n),IO效率随着fd数量增多而线性下降
poll
先来看看poll的函数声明:
int poll (struct pollfd *fds, unsigned int nfds, int timeout);
1
pollfd是表示文件描述符集合的数据结构。
struct pollfd {
int fd; //文件描述符
short events; //监视的请求事件
short revents; //已发生的事件
};
1
2
3
4
5
poll与select差不多,但poll的pollfd没有最大数量的限制,可是IO效率依旧没有提升orz。
epoll
select/poll都只有一个方法,而epoll的操作过程有3个方法,分别是epoll_create(), epoll_ctl(),epoll_wait()。
epoll_create()
int epoll_create(int size);//用于创建一个epoll的句柄,size是指监听的描述符个数。
1
该方法会在内核创建专属于epoll的高速cache区,并在该缓冲区建立红黑树和就绪链表,用户态传入的文件句柄将被放到红黑树中。
epoll_ctl()
int epoll_ctl(int epfd, int op, int fd, struct epoll_event *event);
1
该方法对epoll_create()所创建的内核cache区进行操作的,操作对象是需要监听的fd。
比如,把要监听的fd注册到cache内,那么epoll_ctl()会将fd插入到红黑树中,并向内核注册了该fd的回调函数。内核在检测到某fd可读可写时则调用该回调函数,而回调函数的工作是将fd放到就绪链表。
epoll_wait()
int epoll_wait(int epfd, struct epoll_event *events,int maxevents, int timeout);
1
epoll_wait只需监控就绪链表,如果就绪链表有fd,则表示该fd可读可写,并返回给用户态(少量的copy);
该函数返回需要处理的事件数目,如返回0表示已超时。
小结
执行epoll_create时,在创建了红黑树和就绪链表。执行epoll_ctl时,如果增加fd,则检查在红黑树中是否存在,存在立即返回,不存在则添加到树上,然后向内核注册回调函数,用于当中断事件到来时向准备就绪链表中插入数据。执行epoll_wait时返回就绪链表里的数据即可。
因此,epoll比select和poll高效的原因是:
减少了用户态和内核态之间文件句柄的copy
降低了在文件句柄集中查找的时间复杂度。用红黑树维护fd集,可以将查找fd的时间复杂度降为o(logn)。
参考
https://www.zhihu.com/question/20122137
http://www.jianshu.com/p/dfd940e7fca2#
http://gityuan.com/2015/12/06/linux_epoll/
转--select/poll/epoll到底是什么一回事的更多相关文章
- Python异步非阻塞IO多路复用Select/Poll/Epoll使用,线程,进程,协程
1.使用select模拟socketserver伪并发处理客户端请求,代码如下: import socket import select sk = socket.socket() sk.bind((' ...
- Linux IO模式以及select poll epoll详解
一 背景 同步IO和异步IO,阻塞IO和非阻塞IO分别是什么,到底有什么区别?不同的人在不同的上下文下给出的答案是不同的.所以先限定一下本文的上下文. 本文讨论的背景是Linux环境下的network ...
- select/poll/epoll on serial port
In this article, I will use three asynchronous conferencing--select, poll and epoll on serial port t ...
- Linux下select&poll&epoll的实现原理(一)
最近简单看了一把 linux-3.10.25 kernel中select/poll/epoll这个几个IO事件检测API的实现.此处做一些记录.其基本的原理是相同的,流程如下 先依次调用fd对应的st ...
- Python之路-python(Queue队列、进程、Gevent协程、Select\Poll\Epoll异步IO与事件驱动)
一.进程: 1.语法 2.进程间通讯 3.进程池 二.Gevent协程 三.Select\Poll\Epoll异步IO与事件驱动 一.进程: 1.语法 简单的启动线程语法 def run(name): ...
- 多进程、协程、事件驱动及select poll epoll
目录 -多线程使用场景 -多进程 --简单的一个多进程例子 --进程间数据的交互实现方法 ---通过Queues和Pipe可以实现进程间数据的传递,但是不能实现数据的共享 ---Queues ---P ...
- Python自动化 【第十篇】:Python进阶-多进程/协程/事件驱动与Select\Poll\Epoll异步IO
本节内容: 多进程 协程 事件驱动与Select\Poll\Epoll异步IO 1. 多进程 启动多个进程 进程中启进程 父进程与子进程 进程间通信 不同进程间内存是不共享的,要想实现两个进程间 ...
- select,poll,epoll的归纳总结区分
Select.Poll与Epoll比较 以下资料都是来自网上搜集整理.引用源详见文章末尾. 1 Select.Poll与Epoll简介 Select select本质上是通过设置或者检查存放fd标志位 ...
- 转一贴,今天实在写累了,也看累了--【Python异步非阻塞IO多路复用Select/Poll/Epoll使用】
下面这篇,原理理解了, 再结合 这一周来的心得体会,整个框架就差不多了... http://www.haiyun.me/archives/1056.html 有许多封装好的异步非阻塞IO多路复用框架, ...
随机推荐
- SQL循环语句 详解
SQL循环语句 declare @i int set @i=1 while @i<30 begin insert into test (userid) values(@i) set @i=@i+ ...
- WINDOWS 包管理器 Chocolatey
https://chocolatey.org/ - 官网 安装: @"%SystemRoot%\System32\WindowsPowerShell\v1.0\powershell.exe& ...
- Apache 安装及常用参数设置
禁用 selinux setenforce 0 sed -i "s/SELINUX=enforcing/SELINUX=disabled/g" /etc/selinux/confi ...
- 【HDU3032】Nim or not Nim?(博弈论)
[HDU3032]Nim or not Nim?(博弈论) 题面 HDU 题解 \(Multi-SG\)模板题 #include<iostream> #include<cstdio& ...
- 【BZOJ3215/3216】[ZJOI2013]话旧/话旧2(组合数学,动态规划)
[BZOJ3215/3216][ZJOI2013]话旧/话旧2(组合数学,动态规划) 题面 BZOJ3215 BZOJ3216 题解 先解决\(3216\),求的是最小值为\(0\). 因为起点就是\ ...
- stm32使用rt-thread在文件《stm32f1xx_hal.h》中头文件包含顺序引出的错误
@2019-01-24 [小记] 在学习 rt-thread BSP制作过程中,发现文件<stm32f1xx_hal.h>中 Env工具生成的原始顺序 1. #include " ...
- (二)flask-sqlalchemy基本操作
对数据库基本操作 在Flask-SQLAlchemy中,插入.修改.删除操作,均由数据库会话管理. 会话用 db.session 表示.在准备把数据写入数据库前,要先将数据添加到会话中然后调用 db. ...
- 使用python简单连接并操作数据库
python中连接并操作数据库 图示操作流程 一.使用的完整流程 # 1. 导入模块 from pymysql import connect # 2. 创建和数据库服务器的连接,自行设置 服务器地址, ...
- QML学习笔记(七)— 实现可拖拽、编辑、选中的ListView
鼠标单击可选中当前项,头部呈绿色显示:按压当前项可进行拖拽更换列表项位置:点击数据可以进行编辑: GitHub:八至 作者:狐狸家的鱼 这里是自己定义的model,有些字体和颜色都是使用的全局属性, ...
- 题解-洛谷P1020P导弹拦截(求单调序列长度的优化)
https://www.luogu.org/problemnew/show/P1020 (原题链接) 第一问就是求最长不上升子序列的长度,自然就想到了c++一本通里动态规划里O(n^2)的算法,但题目 ...