美文网首页
java-水平触发和边缘触发区别

java-水平触发和边缘触发区别

作者: coderljx | 来源:发表于2019-03-06 18:44 被阅读0次

    转载自:https://www.jianshu.com/p/7eaa0224d797

    select和poll都只提供了一个函数:select或者poll函数。
    而epoll提供了三个函数,epoll_create,epoll_ctl和epoll_wait,epoll_create是创建一个epoll句柄;epoll_ctl是注册要监听的事件类型;epoll_wait则是等待事件的产生。
    epoll除了提供select/poll那种IO事件的水平触发(Level Triggered)外,还提供了边缘触发(Edge Triggered),这就使得用户空间程序有可能缓存IO状态,减少epoll_wait/epoll_pwait的调用,提高应用程序效率。
    水平触发(level-trggered)
    只要文件描述符关联的读内核缓冲区非空,有数据可以读取,就一直发出可读信号进行通知,
    当文件描述符关联的内核写缓冲区不满,有空间可以写入,就一直发出可写信号进行通知
    LT模式支持阻塞和非阻塞两种方式。epoll默认的模式是LT。
    边缘触发(edge-triggered)
    当文件描述符关联的读内核缓冲区由空转化为非空的时候,则发出可读信号进行通知,
    当文件描述符关联的内核写缓冲区由满转化为不满的时候,则发出可写信号进行通知
    两者的区别在哪里呢?水平触发是只要读缓冲区有数据,就会一直触发可读信号,而边缘触发仅仅在空变为非空的时候通知一次,
    LT(level triggered)是缺省的工作方式,并且同时支持block和no-block socket.在这种做法中,内核告诉你一个文件描述符是否就绪了,然后你可以对这个就绪的fd进行IO操作。如果你不作任何操作,内核还是会继续通知你的,所以,这种模式编程出错误可能性要小一点。传统的select/poll都是这种模型的代表.
    水平触发和边缘触发模式区别

    读缓冲区刚开始是空的
    读缓冲区写入2KB数据
    水平触发和边缘触发模式此时都会发出可读信号
    收到信号通知后,读取了1kb的数据,读缓冲区还剩余1KB数据
    水平触发会再次进行通知,而边缘触发不会再进行通知
    所以,边缘触发需要一次性的把缓冲区的数据读完为止,也就是一直读,直到读到EGAIN为止,EGAIN说明缓冲区已经空了,因为这一点,边缘触发需要设置文件句柄为非阻塞

    //水平触发
    ret = read(fd, buf, sizeof(buf));

    //边缘触发
    while(true) {
    ret = read(fd, buf, sizeof(buf);
    if (ret == EAGAIN) break;
    }

    设置方法
    int epoll_ctl(int epfd, int op, int fd, struct epoll_event event);
    epoll的事件注册函数,它不同与select()是在监听事件时告诉内核要监听什么类型的事件,而是在这里先注册要监听的事件类型。
    第一个参数是epoll_create()的返回值,
    第二个参数表示动作,用三个宏来表示:
    EPOLL_CTL_ADD:注册新的fd到epfd中;
    EPOLL_CTL_MOD:修改已经注册的fd的监听事件;
    EPOLL_CTL_DEL:从epfd中删除一个fd;
    第三个参数是需要监听的fd,第四个参数是告诉内核需要监听什么事,struct epoll_event结构如下:
    struct epoll_event {
    __uint32_t events; /
    Epoll events /
    epoll_data_t data; / User data variable */
    };
    events可以是以下几个宏的集合:
    EPOLLIN :表示对应的文件描述符可以读(包括对端SOCKET正常关闭);
    EPOLLOUT:表示对应的文件描述符可以写;
    EPOLLPRI:表示对应的文件描述符有紧急的数据可读(这里应该表示有带外数据到来);
    EPOLLERR:表示对应的文件描述符发生错误;
    EPOLLHUP:表示对应的文件描述符被挂断;
    EPOLLET: 将EPOLL设为边缘触发(Edge Triggered)模式,这是相对于水平触发(Level Triggered)来说的。
    EPOLLONESHOT:只监听一次事件,当监听完这次事件之后,如果还需要继续监听这个socket的话,需要再次把这个socket加入到EPOLL队列里。
    使用示例
    使用ET的例子:nginx
    使用LT的例子:redis

    相关文章

      网友评论

          本文标题:java-水平触发和边缘触发区别

          本文链接:https://www.haomeiwen.com/subject/mcixpqtx.html