Урок 18: неблокирующий ввод-вывод и epoll
Блокирующий ввод-вывод используется по умолчанию — read() ждёт, пока не поступят данные. С O_NONBLOCK read() сразу возвращает EAGAIN, если данных нет. Но как управлять тысячами FD одновременно? epoll решает именно эту задачу — это event loop, который уведомляет нас только тогда, когда FD готов, за O
Блокирующий ввод-вывод — это как стоять в очереди за билетом и ждать. Неблокирующий — это как сказать кассиру «позвони мне, когда будешь готов». epoll — это телефонист на коммутаторе, который управляет тысячами звонков и передаёт вам только те из них, что ждут вашего ответа.
- неблокирующий ввод-вывод
- Режим, в котором вызовы ввода-вывода (read, write, accept) не блокируются. Если данные не готовы, они возвращают -1 с errno=EAGAIN/EWOULDBLOCK. Включается флагом O_NONBLOCK.
- epoll
- Интерфейс Linux для отслеживания событий ввода-вывода на большом наборе файловых дескрипторов. Состоит из epoll_create, epoll_ctl и epoll_wait. Возвращает только готовые FD — O(1) против O(n) у select.
- edge-triggered (ET)
- Режим epoll, в котором событие сообщается только один раз — когда FD переходит из состояния «не готов» в «готов». Требует чтения до EAGAIN каждый раз. Эффективнее, но сложнее.
- level-triggered (LT)
- Режим epoll по умолчанию — событие сообщается каждый раз при вызове epoll_wait, пока FD всё ещё готов. Проще, чем ET, но может вызывать busy-loop, если его не обрабатывать должным образом.
- event loop
- Паттерн программирования, при котором программа ждёт события и обрабатывает их одно за другим — бесконечный цикл, вызывающий epoll_wait и запускающий callback-и. Основа Node.js, Nginx и Triton.