ET和LT触发方式

ET和LT触发方式

ET模式只能通过一种方式(图中红线)。所以ET模式下能被唤醒的情况,LT模式下一定也能被唤醒。我们先来讨论特殊情况(ET模式),再来讨论一般情况(LT模式)。

ET

根据上一节对两种加入rdlist途径的分析,可以得出ET模式下被唤醒(返回就绪)的条件为:
对于读取操
(1) 当buffer由不可读状态变为可读的时候,即由空变为不空的时候。
(2) 当有新数据到达时,即buffer中的待读内容变多的时候。
另外补充一点:
(3) 当buffer中有数据可读(即buffer不空)且用户对相应fd进行epoll_mod IN事件时。
对于情况(1)(2)分别对应图1(a),图1(b)。
这里写图片描述这里写图片描述
对于写操作
(1) 当buffer由不可写变为可写的时候,即由满状态变为不满状态的时候。
(2) 当有旧数据被发送走时,即buffer中待写的内容变少得时候。
另外补充一点:
(3) 当buffer中有可写空间(即buffer不满)且用户对相应fd进行epoll_mod OUT事件时(具体见下节内容)。
对于情况(1)(2)分别对应图2(a),图2(b)。
这里写图片描述这里写图片描述


LT

LT模式下进程被唤醒(描述符就绪)的条件就简单多了,它包含ET模式的所有条件,也就是上述列出的六中读写被唤醒的条件都是用于LT模式。此外,还有更普通的情况LT可以被唤醒,而ET则不理会,这也是我们需要注意的情况。
对于读操作
当buffer中有数据,且数据被读出一部分后buffer还不空的时候,即buffer中的内容减少的时候,LT模式返回读就绪。如下图所示。
这里写图片描述
对于写操作
当buffer不满,又写了一部分数据后扔然不满的的时候,即由于写操作的速度大于发送速度造成buffer中的内容增多的时候,LT模式会返回就绪。如下图所示。
这里写图片描述

注:poll和select都是LT模式。

### LT模式与ET模式的区别及应用场景 #### 区别 1. **触发机制** - 在水平触发LT,Level-Triggered)模式下,当`epoll_wait`检测到文件描述符上有事件发生时,即使应用程序未立即处理该事件,只要事件仍然有效,`epoll_wait`会在后续调用中继续通知该事件[^3]。 - 在边缘触发ET,Edge-Triggered)模式下,`epoll_wait`仅在事件状态从“无事件”变为“有事件”时通知一次。如果应用程序未能完全处理该事件(例如未读取完所有数据或未接受所有连接),则需要自行负责后续的处理[^1]。 2. **事件处理要求** - 在LT模式下,应用程序可以按需读取部分数据,无需一次性将所有数据读取完毕。这允许更灵活的事件处理逻辑[^2]。 - 在ET模式下,应用程序必须确保每次事件触发后都将所有数据读取完毕,或者立即处理完所有待处理的任务(如接受连接)。否则,可能会导致数据丢失或任务延迟[^2]。 3. **性能特性** - LT模式可能因多次重复通知同一事件而增加系统开销,但其逻辑简单,适合对性能要求不高的场景[^3]。 - ET模式通过减少事件通知次数来提高性能,但需要应用程序实现更复杂的事件处理逻辑以避免遗漏未处理的数据。 --- #### 应用场景 1. **LT模式的应用场景** - 适用于对性能要求不高、但希望简化事件处理逻辑的场景。例如,简单的网络服务器或调试工具[^3]。 - 当需要频繁读取小块数据时,LT模式可以避免因未读取完所有数据而导致的复杂处理逻辑[^2]。 2. **ET模式的应用场景** - 适用于高并发、高性能的场景,如大型Web服务器、实时通信系统等。在这种场景下,减少事件通知次数可以显著降低CPU内存开销。 - 当应用程序能够高效地批量处理事件(如一次性读取大量数据或接受多个连接)时,ET模式的优势更加明显[^2]。 --- ### 示例代码 以下是一个简单的ET模式示例,展示如何在`epoll`中处理读事件: ```python import select import socket # 创建监听socket server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) server_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) server_socket.bind(('0.0.0.0', 8080)) server_socket.listen(100) server_socket.setblocking(False) # 初始化epoll epoll = select.epoll() epoll.register(server_socket.fileno(), select.EPOLLIN | select.EPOLLET) connections = {} try: while True: events = epoll.poll(1) for fileno, event in events: if fileno == server_socket.fileno(): # 接受新连接 client_socket, address = server_socket.accept() client_socket.setblocking(False) epoll.register(client_socket.fileno(), select.EPOLLIN | select.EPOLLET) connections[client_socket.fileno()] = client_socket elif event & select.EPOLLIN: # 处理读事件 client_socket = connections[fileno] data = b'' while True: try: chunk = client_socket.recv(4096) if not chunk: break data += chunk except BlockingIOError: break if data: print(f"Received: {data.decode()}") finally: epoll.unregister(server_socket.fileno()) epoll.close() server_socket.close() ``` --- ####
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值