• IO多路复用之Reactor模式


    首先,我们来看看同步和异步。

    在处理 IO 的时候,阻塞和非阻塞都是同步 IO。
    只有使用了特殊的 API 才是异步 IO。

    接下来,我们来看看Linux下的三大同步IO多路复用函数
    fcntl(fd, F_SETFL, O_NONBLOCK);  //socket设为O_NONBLOCK,但是select/poll/epoll是block操作

    1)select
    int select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout);

    缺点:
    1). nfds有限制,最大只能是1024
    2). 知道有事件到来,还要遍历到底是哪个fd触发的
    3).不能动态的修改fdset, 或者关闭某个socket
    4)、需要维护一个用来存放大量fd的数据结构,这样会使得用户空间和内核空间在传递该结构时复制开销大

    优点:(select如此的老,我们还需要它吗?)
    1). 更好的兼容老的系统
    2). select 计算超时可以达到纳秒精度,而poll, epoll只能达到毫秒的精度。client/server用不着这么高,但嵌入式系统用的着。
    事实上,如果你写一个不超过200个socket程序,select和poll, epool性能上没啥区别。


    2)poll
    int poll(struct pollfd *fds,nfds_t nfds, int timeout);

    缺点:
    1). 知道有事件到来,还要遍历到底是哪个fd触发的
    2).不能动态的修改fdset, 或者关闭某个socket

    优点:
    1)没有fd个数限制

    使用场景:
    1)多平台支持,不仅仅是linux,你又不想使用libevent
    2)不超过1000个sockets
    3)超过1000个socket,但是socket都是short-lived的
    4)Your application is not designed the way that it changes the events while another thread is waiting for them


    3)epool (epoll is Linux only)
    int epoll_wait(int epfd, struct epoll_event * events, int maxevents, int timeout);

    1)Your application runs a thread poll which handles many network connections by a handful of threads.
       单线程应用使用epool得不偿失,不比pool好
    2)至少1000个以上的socket,socket
    3)epoll是Linux内核为处理大批量文件描述符而作了改进的poll,是Linux下多路复用IO接口select/poll的增强版本,它能显著提高程序在大量并发连接中只有少量活跃的情况下的系统CPU利用率。另一点原因就是获取事件的时候,它无须遍历整个被侦听的描述符集,只要遍历那些被内核IO事件异步唤醒而加入Ready队列的描述符集合就行了。epoll除了提供select/poll那种IO事件的水平触发(Level Triggered)外,还提供了边缘触发(Edge Triggered),这就使得用户空间程序有可能缓存IO状态,减少epoll_wait/epoll_pwait的调用,提高应用程序效率。

    怎么选择呢?

    如果处理的连接数不是很高的话,使用select/epoll的web server不一定比使用multi-threading + blocking IO的web server性能更好,可能延迟还更大。

    select/epoll的优势并不是对于单个连接能处理得更快,而是在于能处理更多的连接。真正的异步IO(下面会统一叫做AIO)应该像Windows IOCP一样,传入文件句柄,缓存区,尺寸等参数和一个函数指针,当操作系统真正完成了IO操作,再执行对应的函数。

    实际上对于socket来说,epoll已经是最高效的模型了,虽然比AIO多一次recv系统调用,但总体来看没有任何IO等待,效率很高。而且epoll是天然的reactor模型,程序实现更容易。AIO如windows的IOCP,是异步回调的方式,开发难度很高。

    再来说Reactor首先看它的类图,顺便说一句,我向来看不懂类图,我只喜欢序列图

    下面上序列图:

    OK,搞定,看懂了么? 看不懂慢慢看吧

  • 相关阅读:
    ecmall 开发一个新模块
    ecmall 如何新增挂件
    ecmall 主从表的4种模型关系
    ecmall 的一些方法说明
    ecmall 支付成功 订单状态没有改变解决办法
    ecmall 基础类分析
    phpcms 新建模块安装
    phpcms pc_base::load
    strptime()方法
    GDB调试方法精粹
  • 原文地址:https://www.cnblogs.com/awiki/p/6165504.html
Copyright © 2020-2023  润新知