Ответ
epoll — это масштабируемый механизм мультиплексирования ввода-вывода в ядре Linux. Он позволяет приложению эффективно отслеживать готовность большого количества файловых дескрипторов (например, сетевых сокетов) к операциям чтения или записи.
Основное отличие от select и poll в том, что epoll хранит список отслеживаемых дескрипторов в ядре, а не требует передавать его при каждом вызове. Это кардинально снижает накладные расходы.
Ключевые преимущества:
- Масштабируемость O(1): Время выполнения
epoll_wait()зависит только от количества готовых дескрипторов, а не от их общего числа. Уselectиpollсложность O(N), где N — общее число отслеживаемых дескрипторов. - Режимы работы:
- Level-triggered (LT, по умолчанию): Уведомляет о готовности дескриптора, пока условие выполняется (например, пока в буфере есть данные для чтения).
- Edge-triggered (ET): Уведомляет о событии только один раз при изменении состояния (например, при поступлении новых данных в буфер). Этот режим требует более аккуратной обработки, но обеспечивает максимальную производительность.
- Эффективность: Избавляет от необходимости каждый раз копировать большие наборы дескрипторов между пространством пользователя и ядром.
Пример использования (Python):
import select
import socket
server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server.setblocking(False)
server.bind(('0.0.0.0', 8080))
server.listen(128)
# Создаем epoll объект
epoll = select.epoll()
# Регистрируем серверный сокет на событие входящего чтения (новое соединение)
epoll.register(server.fileno(), select.EPOLLIN)
connections = {}
try:
while True:
# Ожидаем события, таймаут 1 секунда
events = epoll.poll(1)
for fd, event in events:
# Если событие на серверном сокете - принимаем новое соединение
if fd == server.fileno():
client, addr = server.accept()
client.setblocking(False)
epoll.register(client.fileno(), select.EPOLLIN)
connections[client.fileno()] = client
# Если событие на клиентском сокете - читаем данные
elif event & select.EPOLLIN:
client_socket = connections[fd]
data = client_socket.recv(1024)
if not data:
# Клиент закрыл соединение
epoll.unregister(fd)
client_socket.close()
del connections[fd]
finally:
epoll.close()
server.close()