IO多路复用模型

一、背景:使用管道进行通信时,即使输入设备缓冲区或者管道读缓冲区当中的某一个存在数据时,整个进程也会处于阻塞状态。

即使有数据也会出现阻塞的原因,要么是进程read管道文件时,输入设备缓冲区有数据而管道缓冲区无数据;要么就是进程read输入设备时,输入设备缓冲区无数据而管道缓冲区有数据——究其根本,就是多个read的等待是串行的而不是并行的。

 要想解决上述多个资源的读取操作引发的阻塞问题,一种自然的思路就是将串行的等待改成并行的等待。操作系统提供了一种I/O多路复用机制来实现这种并行的等待;当进程使用I/O多路复用系统调用时,进程陷入等待状态;而此时操作系统可以监听多个文件描述符是否就绪(也就是文件缓冲区中是否存在数据);当监听的多个文件描述符中至少存在一个文件描述符就绪的时候,操作系统就可以唤醒进程,随后进程就可以遍历就绪的文件描述符,再执行读取操作(这个读取操作就不会引发阻塞了)。

二、select 使用流程:

  • 首先,需要先为监听集合申请内存;
  • 使用 FD_ZERO 初始化监听集合;
  • 将所有需要监听的文件描述符使用 FD_ZERO 加入监听集合;
  • 调用 select 系统调用使进程陷入阻塞状态;
  • 从阻塞当中被唤醒以后,可以遍历所有监听的文件描述符,找到真正就绪的文件描述符;
  • 对就绪的文件描述符执行IO操作。

三、select和poll的执行原理是一样的:

1、将当前进程的所有文件描述符,一次性的从用户态拷贝到内核态。

2、在内核态中快速的无差别的遍历每个fd,判断是否有数据到达。

3、将所有fd状态,从内核态拷贝到用户态,并返回已就绪的fd的个数。 

4、在用户态遍历判断具体哪个fd已就绪,然后进行相应的事件处理。

四、select的不足:

1、文件描述符表为bitmap结构,且有长度为1024的限制。

2、fdset无法做到重用,每次循环必须重新建立。

3、频繁的用户态和内核态拷贝,性能开销较大。

4、需要对文件描述符表进行遍历,O(n)的轮询时间复杂度。

五、poll的解决的问题和不足

1、poll模型采用pollfd数据结构,解决了select的1024个文件描述符的限制。

2、但仍然存在频繁的用户态和内核态的拷贝,性能开销较大。

3、需要对文件描述符表进行遍历,O(n)的轮询时间复杂度。

六、epoll

1、在epoll_ctl()函数中,为每个文件描述符都指定了回调函数,基于回调函数把就绪时间放到就绪队列中,因此把时间复杂度从o(n)降到了O(1)。

2、只需要在调用epoll_ctl()时传递一次文件描述符,epoll_wait()不需要再次传递文件描述符。

3、epoll基于红黑树+双链表存储事件,没有最大连接数的限制。

七、使用场景

1、如果你正在编写一个需要处理大量并发连接或高并发的服务器应用程序并且你的应用程序运行在Linux上,那么应该使用epoll。

2、如果你的应用程序不需要处理大量并发连接,或者你的应用程序不是运行在Linux上,那么你可以考虑使用select或poll。但是,请注意select和poll在处理大量文件描述符时的性能问题。

3、在某些情况下,如果知道应用程序只会使用很少量的文件描述符,并且你不需要处理大量的并发连接,那么使用select 或poll 也是可以接受的。

八、水平触发和边缘触发的区别

对于需要高效处理大量数据且对实时性要求较高的场景,边缘触发模式可能更合适。而对于需要更灵活处理读写操作且对实时性要求不是非常高的场景,水平触发模式可能更易于实现和维护。 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值