IO多路复用

概述

IO多路复用是一种同步IO模型,实现一个线程可以监视多个文件句柄

  • 一旦某个文件句柄就绪,就能够通知应用程序进行相应的读写操作;
  • 没有文件句柄就绪时会阻塞应用程序,交出cpu;
  • 多路是指网络连接,复用指的是同一个线程。

三种实现方式

select

  • 时间复杂度O(n),它仅仅知道了,有I/O事件发生了,却并不知道是哪那几个流(可能有一个,多个,甚至全部),
  • 只能无差别轮询所有流,找出能读出数据,或者写入数据的流,对他们进行操作。
  • 所以select具有O(n)的无差别轮询复杂度,同时处理的流越多,无差别轮询时间就越长。
实现
 int select (int n, fd_set *readfds, fd_set *writefds, 
             fd_set *exceptfds, struct timeval *timeout);

select 函数监视的文件描述符分3类,分别是writefds、readfds、和exceptfds。
调用后select函数会阻塞,直到有:

  • 描述符就绪(有数据可读、可写、或者有except)
  • 超时(timeout指定等待时间,如果立即返回设为null即可)
  • 函数返回。

当select函数返回后,可以通过遍历fdset,来找到就绪的描述符。

优缺点
  • 良好的跨平台支持,select目前几乎在所有的平台上支持。
  • 单个进程能够监视的文件描述符的数量存在最大限制,在Linux上一般为1024可以修改限制,但是这样也会造成效率的降低。

poll

时间复杂度O(n),poll本质上和select没有区别,它将用户传入的数组拷贝到内核空间,然后查询每个fd对应的设备状态,

  • 没有最大连接数的限制,原因是它是基于链表来存储的。
int poll (struct pollfd *fds, unsigned int nfds, int timeout);
实现

poll使用一个 pollfd的指针实现。

struct pollfd {
    int fd;            /* file descriptor */
    short events;      /* requested events to watch */
    short revents;     /* returned events witnessed */
};
优缺点

pollfd结构包含了要监视的event和发生的event,不再使用select“参数-值”传递的方式。

  • pollfd并没有最大数量限制(但是数量过大后性能也是会下降)
  • 和select函数一样,poll返回后,需要轮询pollfd来获取就绪的描述符。

epoll

时间复杂度O(1),epoll可以理解为event poll,不同于忙轮询和无差别轮询,epoll会把哪个流发生了怎样的I/O事件通知我们。

  • epoll实际上是事件驱动(每个事件关联上fd)的,此时对这些流的操作都是有意义的。
实现

epoll操作过程需要三个接口,分别如下:

int epoll_create(int size);
int epoll_ctl(int epfd, int op, int fd, struct epoll_event *event);
int epoll_wait(int epfd, struct epoll_event * events, 
               int maxevents, int timeout);
int epoll_create(int size)
  • 创建一个epoll的句柄,size用来告诉内核这个监听的数目一共有多大,这个参数不同于select()中的第一个参数,给出最大监听的fd+1的值
  • 参数size并不是限制了epoll所能监听的描述符最大个数,只是对内核初始分配内部数据结构的一个建议。
  • 当创建好epoll句柄后,它就会占用一个fd值,在使用完epoll后,必须调用close()关闭,否则可能导致fd被耗尽。
int epoll_ctl(int epfd, int op, int fd, struct epoll_event *event)

函数是对指定描述符fd执行op操作。

  • epfd:是epoll_create()的返回值。
  • op:表示op操作,用三个宏来表示,分别添加、删除和修改对fd的监听事件。
    • 添加EPOLL_CTL_ADD,
    • 删除EPOLL_CTL_DEL,
    • 修改EPOLL_CTL_MOD。
  • fd:是需要监听的fd(文件描述符)
  • epoll_event:是告诉内核需要监听什么事,
int epoll_wait(int epfd, struct epoll_event * events, 
               int maxevents, int timeout)

等待epfd上的io事件,最多返回maxevents个事件。

  • 参数events用来从内核得到事件的集合
  • maxevents告之内核这个events有多大,这个maxevents的值不能大于创建epoll_create()时的size,
  • 参数timeout是超时时间(毫秒,0会立即返回,-1将不确定,也有说法说是永久阻塞)。该函数返回需要处理的事件数目,如返回0表示已超时。
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值