ET与LT

ET(Edge Triggered,边缘触发)LT(Level Triggered,水平触发)epoll 中两种不同的事件触发模式。

它们的主要区别在于通知事件的时机与处理事件的方式不同:


一、含义与区别:

模式含义(直观理解)事件通知条件
LT (默认)只要有数据未处理完,内核会一直通知(重复触发)状态触发,多次通知
ET数据到达时仅通知一次,必须全部读完才有下一次通知边缘触发,只通知一次

一、详细解释与区别

(1)LT模式(默认)

  • 含义

    内核只要发现描述符处于就绪状态,就会不断通知应用程序。
    例如,有数据未读完时,epoll会一直告诉你“可读”。

例子说明

  • 假如有10字节的数据到来,而你只读取了其中的5字节。
  • 下一次调用epoll_wait时,它仍然会提醒你有数据可读,直到所有数据都读取完为止。

代码示例(LT模式):

epoll_event ev;
ev.events = EPOLLIN; // 默认是LT模式
ev.data.fd = fd;
epoll_ctl(epfd, EPOLL_CTL_ADD, fd, &ev);

// 每次调用epoll_wait都会返回fd,直到缓冲区完全为空
int nfds = epoll_wait(epfd, events, MAX_EVENTS, -1);

二、边缘触发(ET)的特点:

ET模式下:

  • 当被监控的文件描述符状态发生变化时,内核仅通知一次
  • 必须一次性完整处理完数据,直到EAGAINEWOULDBLOCK返回为止。
  • 如果未读完数据,epoll不会再次通知,这可能导致遗漏数据(或事件)!

因此,在ET模式下,必须采用非阻塞方式,一次读完数据

代码示例(ET模式下正确做法):

epoll_event ev;
ev.events = EPOLLIN | EPOLLET; // 使用ET模式
ev.data.fd = fd;
epoll_ctl(epfd, EPOLL_CTL_ADD, fd, &ev);

// ET模式下的正确读取方式:
while (true) {
    int n = read(fd, buf, sizeof(buf));
    if (n == -1) {
        if (errno == EAGAIN || errno == EWOULDBLOCK) {
            // 已经没有数据可读了,退出循环
            break;
        }
        // 其他错误处理
    } else if (n == 0) {
        // 对端关闭了连接
        break;
    } else {
        // 成功读取数据,继续循环直到读完
    }
}

三、LT与ET对比:

对比项LT(默认)ET
触发次数只要有数据就一直通知(重复)数据到达时仅通知一次
读取方式可一次读完或多次读取必须一次性全部读取完毕
漏读风险基本没有如果没全部读完,可能漏读
使用复杂度简单较复杂,需额外处理逻辑
性能低一些更高效,更适合高性能场景

四、ET 和 LT 适用场景:

  • LT模式适用于简单场景,比如小型服务、对性能要求不高的应用,尤其是不确定数据何时读完的场景。
  • ET模式特别适合高并发服务器
    • 减少事件重复通知的开销。
    • 强制程序一次性处理完所有数据,效率更高。

四、实际应用建议:

  • 一般建议使用ET模式以提高性能,但要特别注意:
    • 必须使用非阻塞IO
    • 循环读写直到返回EAGAIN为止,以避免漏读数据。

如果对性能要求不高,且为了方便起见,可以选择使用LT模式。


五、小结(直观对比):

  • LT模式:
    • 内核告诉你:『fd可以读了』。
    • 如果你没读完,下次还继续提醒你。
  • ET模式:
    • 内核只告诉你一次:『fd状态变了,有数据可读』。
    • 如果你不一次读完,下次不会再提醒你(直到下次新数据到来)。

因此:

场景推荐模式
高性能服务器ET
普通场景、简便程序LT(默认)

希望以上能彻底解答你的疑惑!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值