针对IO,总是涉及到阻塞、非阻塞、异步、同步以及select/poll和epoll的一些描述,那么这些东西到底是什么,有什么差异?
一般来讲一个IO分为两个阶段:
等待数据到达
把数据从内核空间拷贝到用户空间
现在假设一个进程/线程A,试图进行一次IO操作。
A发出IO请求,两种情况:
1)立即返回
2)由于数据未准备好,需要等待,让出CPU给别的线程,自己sleep
第一种情况就是非阻塞,A为了知道数据是否准备好,需要不停的询问,而在轮询的空歇期,理论上是可以干点别的活,例如喝喝茶、泡个妞。
第二种情况就是阻塞,A除了等待就不能做任何事情。
数据终于准备好了,A现在要把数据取回去,有几种做法: 1)A自己把数据从内核空间拷贝到用户空间。
2)A创建一个新线程(或者直接使用内核线程),这个新线程把数据从内核空间拷贝到用户空间。
第一种情况,所有的事情都是同一个线程做,叫做同步,有同步阻塞(BIO)、同步非阻塞(NIO)
第二种情况,叫做异步,只有异步非阻塞(AIO)
同步阻塞:
同一个线程在IO时一直阻塞,直到读取数据成功,把数据从核心空间拷贝到用户空间
同步非阻塞:
同一个线程发起IO后,立即获得返回,后面定期轮询数据读取情况,发现数据读取成功,把数据从核心空间拷贝到用户空间
异步非阻塞:
一个线程发起IO后,立即返回,由另外的线程发现数据读取成功,把数据从核心空间拷贝到用户空间。
下面说一下多路复用:select/poll、epoll
select是几乎所有unix、linux都支持的一种多路IO方式,通过select函数发出IO请求后,线程阻塞,一直到数据准备完毕,然后才能把数据从核心空间拷贝到用户空间,所以select是同步阻塞方式。
int select(int n, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout);
参数n表示监控的所有fd中最大值+1
readfds、writefds和exceptfds分别表示可读、可写、异常的文件句柄,这个文件句柄中每一个bit表示一个文件fd,所以能够表示的最大文件数和fd_set的长度有关,
假设fd_set的长度为1字节(即8bit),则可以表示8个可读文件、8个可写文件、8个异常文件句柄。下面以读文件为例:
使用select的时候,先初始化FD_ZERO(fd_set *set),把8bit全部置为0,readfds=00000000
使用FD_SET(int fd, fd_set *set)来把文件fd设置到fd_set中,例如3个文件fd=2,fd=3,fd=5,则readfds=00010110
然后使用select(6, readfds, 0, 0, 0)阻塞等待,若此时fd=2文件可读,则此时readfds=00000010(fd=5和fd=3对应的bit被清0)
使用FD_ISSET(int fd, fd_set *set)函数来判断fd对应的bit是否为1,如果为1则可读。
poll对select的使用方法进行了一些改进,突破了最大文件数的限制,同时使用更加方便一些。
int poll(struct pollfd *ufds, unsigned int nfds, int timeout);
struct pollfd {
int fd; /* 对应的文件描述符 */
short events; /* 要监听的事件,例如POLLIN|POLLPRI */
short revents; /* 返回的事件,用于在poll返回时携带该fd上发生的事情,在poll调用时,该字段会自动被清空 */
};
通过poll函数发出IO请求后,线程阻塞,直到数据准备完毕,poll函数在pollfd中通过revents字段返回事件,然后线程把数据从核心空间拷贝到用户空间,
所以poll同样是同步阻塞方式,性能同select相比没有改进。
epoll是linux为了解决select/poll的性能问题而新搞出来的机制,基本的思路是:由专门的内核线程来不停地扫描fd列表,有结果后,把结果放到fd相关的链表中,
用户线程只需要定期从该fd对应的链表中读取事件就可以了。同时,为了节省把数据从核心空间拷贝到用户空间的消耗,采用了mmap的方式,允许程序在用户空间直接访问数据所在的内核空间,不需要把数据copy一份。
epoll一共有3个函数:
1.创建epoll文件描述符
int epoll_create(int size);
2.把需要监听的文件fd和事件加入到epoll文件描述符,也可以对已有的fd进行修改和删除
文件fd保存在一个红黑树中,该fd的事件保存在一个链表中(每个fd一个事件链表),事件由内核线程负责填充,用户线程读取
int epoll_ctl(int epfd, int op, int fd, struct epoll_event *event);
typedef union epoll_data {
void *ptr;
int fd;
__uint32_t u32;
__uint64_t u64;
} epoll_data_t;
struct epoll_event {
__uint32_t events; /* Epoll events */
epoll_data_t data; /* User data variable */
};
3.用户线程定期轮询epoll文件描述符上的事件,事件发生后,读取事件对应的epoll_data,该结构中包含了文件fd和数据地址,由于采用了mmap,程序可以直接读取数据。
int epoll_wait(int epfd, struct epoll_event * events, int maxevents, int timeout);
有人把epoll这种方式叫做同步非阻塞(NIO),因为用户线程需要不停地轮询,自己读取数据,看上去好像只有一个线程在做事情
也有人把这种方式叫做异步非阻塞(AIO),因为毕竟是内核线程负责扫描fd列表,并填充事件链表的
个人认为真正理想的异步非阻塞,应该是内核线程填充事件链表后,主动通知用户线程,或者调用应用程序事先注册的回调函数来处理数据,如果还需要用户线程不停的轮询来获取事件信息,就不是太完美了,所以也有不少人认为epoll是伪AIO,还是有道理的。
另外一个epoll的变化,是支持了边沿触发,以前select/poll中,每次遍历fd列表,发现fd可写、可读或异常后,就把bit置1(select)或返回对应事件(poll),
而在epoll中,同样支持这种方式,每次fd可写、可读或异常后,就写入事件到事件链表中,还支持只在事件发生变化时才写入事件链表,例如如果事件一直是可读,则只在第一次写入链表
业界把这两种方式分别叫做电平触发和边沿触发,像电信号(方波)一样,从高电平到低电平或低电平到高电平的“拐角”处的触发,叫做边沿触发,其他上下两个平面上的连续触发叫电平触发
epoll支持电平触发(Level Triggered)和边沿触发(Edge Triggered),默认为电平触发
- 大小: 21.9 KB
- 大小: 33.7 KB
- 大小: 27.4 KB
分享到:
相关推荐
同步与异步、阻塞与非阻塞是网络编程中的重要概念。阻塞式 socket 在等待数据时会挂起,直到有数据可读或写操作完成。而非阻塞式 socket 在无数据可读或写操作未完成时不会挂起,而是立即返回错误。异步编程则进一步...
根据提供的文件信息,本文将会深入分析poll和epoll两种I/O多路复用技术的源码,并且阐述其工作原理及效率差异。 首先,poll和epoll都是Linux系统中用于处理大量文件描述符(file descriptor,简称fd)的I/O多路复用...
与传统的`select`和`poll`相比,`epoll`具有显著的优势,如更高的性能和更好的可扩展性。 首先,`epoll_create`函数用于创建一个`epoll`实例,返回一个专用的文件描述符。这个文件描述符用于后续的`epoll_ctl`和`...
【EPOLL - Linux 下的 Select 和 Poll 增强版】 EPOLL 是 Linux 内核提供的 I/O 多路复用技术,它是 Select 和 Poll 的更高效版本,特别是在处理大量并发连接时。EPOLL 提供了一种基于事件的异步 I/O 模型,能够...
- **线程模型**:epoll更适合多线程同步模型,而iocp更适合异步I/O模型。 - **兼容性**:epoll是Linux特有,而iocp仅限于Windows。 5. **实际应用** - **epoll**常用于高性能服务器,如Web服务器、数据库服务器...
### 一文理解异步同步阻塞与非阻塞 #### 同步与异步 ...通过以上的解释和示例,我们可以更好地理解同步与异步、阻塞与非阻塞以及不同I/O模型之间的差异。这些概念对于软件开发特别是高性能服务器端开发非常重要。
此外,还有多路复用I/O模型,如 select、poll 和 epoll,它们允许单个线程监视多个文件描述符,当其中任何一个描述符就绪时,系统会通知程序。这种方式特别适用于需要同时处理多个连接的服务器应用。 在编写设备...
总结来说,Linux网络编程中的同步和异步、阻塞和非阻塞的选择取决于应用场景的需求。阻塞I/O简单易用,适合单线程、顺序执行的任务;非阻塞I/O和IO多路复用适合多任务并行处理;异步I/O则为高性能、高并发的系统设计...
epoll是Linux内核提供的I/O复用接口,它扩展了select和poll的功能,可以高效地处理大量并发连接。在C语言爬虫中,epoll用于监控socket连接的状态,例如连接建立、数据可读或可写等事件。当epoll_wait检测到某个事件...
Netty 面试题 20 道,涵盖 Netty 基础知识、NIO 框架、IO 模型、多路...select、poll 和 epoll 都可以用来处理高并发的连接,但是它们的性能和限制不同。select 和 poll 适合小规模的连接,而 epoll 适合大规模的连接。
4. **事件驱动编程**:例如使用`select()`, `poll()`, 或 `epoll()`等系统调用来监控多个套接字的事件,当有事件发生时进行相应的处理。 5. **回调函数**:当网络事件发生时,调用预先设定的回调函数,处理数据。 ...
看到这篇文章说明你已经从老版本升级到 Ubuntu16.04或进行了全新安装,在安装好Ubuntu...同步IO和异步IO,阻塞IO和非阻塞IO分别是什么,到底有什么区别?不同的人在不同的上下文下给出的答案是不同的。所以先限定一下本
2. **select()、poll() 和 epoll() 系统调用**: - **select()**:允许程序监控多个文件描述符,当它们中的任何一个准备就绪(即可以进行读写操作)时,select()会唤醒程序。但是,select()存在文件描述符数量的...
3. **异步阻塞I/O**:结合了非阻塞I/O和阻塞通知机制,如select/poll/epoll,用于检测I/O描述符的状态变化。虽然提供了多描述符通知的便利,但在高性能场景下效率不足。 4. **异步非阻塞I/O(AIO)**:真正实现了I/O...
7. `select()`/`poll()`/`epoll()`:异步非阻塞模式下,这些函数用于检测socket上的可读写事件,从而避免阻塞。 在这个项目中,"SocketAsynServer"可能实现了服务器端的逻辑,包括创建监听socket、接受客户端连接、...
在进行网络编程时,Socket通信是基础,而同步与异步、阻塞与非阻塞的概念则是理解Socket通信的关键。同步与异步关注的是程序调用的返回方式,而阻塞与非阻塞则涉及线程的状态。 同步与异步: 同步调用是一种同步...
epoll 是 Linux 内核中的一种用于高效处理大量并发 I/O 请求的技术,它作为 select 和 poll 的升级版,极大地提高了处理大规模文件描述符(FD)的能力。epoll 通过优化内核与用户空间之间的交互以及对活跃描述符的...
Linux提供了多种I/O模型,包括阻塞I/O、非阻塞I/O、I/O复用(select、poll、epoll)、信号驱动I/O和异步I/O。本文主要关注的是I/O复用模型中的epoll。 **Linux网络I/O模型的演进过程** 早期的Linux系统中,服务器...
Epoll 相比于传统的 select/poll 机制有以下优点: * 高效:Epoll 使用红黑树来存储文件描述符,查找和插入操作的时间复杂度为 O(log N)。 * 可扩展性好:Epoll 可以同时处理大量的文件描述符,理论上没有限制。 * ...