标签:函数返回 之间 方案 参考 body epo int 复杂度 mic
在深入理解select、poll和epoll之间的区别之前,首先要了解什么是IO多路复用模型。
简单来说,IO多路复用是指内核一旦发现进程指定的一个或者多个IO条件准备就绪,它就通知该进程去进行IO操作。
详细的描述可以参考IO模型。select、poll和epoll都是提供I/O多路复用的解决方案。
int select(int maxfdp, fd_set *readset, fd_set *writeset,
fd_set *exceptset, struct timeval *timeout);
writefds
、readfds
、和exceptfds
。调用select时会被阻塞,直到有fd就绪(读、写、或者异常),或者超时(timeout
指定等待时间,如果立即返回设为null
即可)函数返回一个大于0
的值,然后通过遍历文件描述符集合fd_set
,来找到就绪的描述符maxfdp
是一个整数值,是指集合中所有文件描述符的范围,即所有文件描述符的最大值加1。fd_set
是以位图的形式来存储这些文件描述符。maxfdp
也就是定义了位图中有效地位的个数O(n)
,n
为文件描述符集合fd_set
的大小1024
int poll ( struct pollfd * fds, unsigned int nfds, int timeout);
struct pollfd
结构类型的数组,用于存放需要检测其状态的所有文件描述符。调用poll函数之后,系统不会清空这个数组。特别是对于文件描述符比较多的情况下,在一定程度上可以提高处理的效率。这一点与select()函数不同,调用select()函数之后,select()函数会清空它所检测的文件描述符集合,导致每次调用select()之前都必须把文件描述符重新加入到待检测的集合中。因此,select()函数适合于只检测一个文件描述符的情况,而poll()函数适合于大量文件描述符的情况O(n)
,n
为文件描述符集合的大小fds
是一个链表// 建立一个epoll对象,参数size是内核保证能够正确处理的最大句柄数
int epoll_create(int size);
// 操作上面建立的epoll
// 例如,将刚建立的socket加入到epoll中让其监控,或者
// 把 epoll正在监控的某个socket句并移出epoll
int epoll_ctl(int epfd, int op, int fd, struct epoll_event *event);
// 在指定的timeout时间内,当所有句柄中有事件发生时,就返回给用户态的进程
int epoll_wait(int epfd, struct epoll_event * events, int maxevents, int timeout);
fd_set
存储在共享内存(用户空间和内核空间都可以直接访问)。调用epoll_create
函数创建epoll对象,并以红黑树的结构存储在内核空间,epoll_ctl
函数用来在红黑树中添加或者注销待监视文件描述符,最后调用epoll_wait
函数直到有就绪的文件描述符立即返回给用户态进程O(1)
1024
(1G
的内存上能监听约10w+
)ET模式的效率比LT模式的效率要高很多。只是如果使用ET模式,就要保证每次进行数据处理时,要将其处理完,不能造成数据丢失,这样对编写代码的人要求就比较高。?为了保证数据的完整性,ET模式只支持非阻塞的读写。
实现机制 | 时间复杂度 | 连接数 | 传递方式 |
---|---|---|---|
select | O(n) |
1024 |
内核-->用户 |
poll | O(n) |
无限制 | 内核-->用户 |
epoll | O(1) |
很大 | 共享内存 |
在select和poll中,进程只有在调用方法后,内核才对所有监视的文件描述符进行扫描,发现有任何一个文件描述符就绪或者超时就立刻返回。epoll采用基于事件的就绪通知方式,事先通过epoll_ctl()来注册一个文件描述符,一旦基于某个文件描述符就绪时,内核会采用类似callback的回调机制,迅速激活这个文件描述符,当进程调用epoll_wait()时便得到通知。
标签:函数返回 之间 方案 参考 body epo int 复杂度 mic
原文地址:https://www.cnblogs.com/pinxiong/p/13288140.html