(Недавний письменный тест столкнулся с письменными тестовыми вопросами: select, poll, epoll — все это механизмы мультиплексирования ввода-вывода).
Мультиплексирование ввода/вывода использует механизм для мониторинга нескольких дескрипторов.Когда дескриптор готов (обычно готов к чтению или записи), он может уведомить программу о выполнении соответствующих операций чтения и записи. Но select, poll и epoll по сути являются синхронным вводом-выводом, потому что все они должны отвечать за чтение и запись после того, как события чтения и записи готовы, то есть процесс чтения и записи блокируется, а асинхронный ввод-вывод /O не требует собственного Отвечает за чтение и запись, реализация асинхронного ввода-вывода будет отвечать за копирование данных из ядра в пространство пользователя. Что касается использования этих трех операций мультиплексирования ввода-вывода, предыдущие три сводки очень ясны, и они протестированы с помощью программы эха сервера.
Выберите сводку мультиплексирования ввода-вывода
Сводка опроса мультиплексирования ввода-вывода
сводка epoll о мультиплексировании ввода-вывода
Соединение выглядит так:
Разбираемся с мультиплексированием IO:
1. Процесс вызова select выглядит следующим образом:
(1)使用copy_from_user从用户空间拷贝fd_set到内核空间
(2)注册回调函数__pollwait
(3)遍历所有fd,调用其对应的poll方法(对于socket,这个poll方法是sock_poll,sock_poll根据情况会调用到tcp_poll,udp_poll或者datagram_poll)
(4)以tcp_poll为例,其核心实现就是__pollwait,也就是上面注册的回调函数。
(5)__pollwait的主要工作就是把current(当前进程)挂到设备的等待队列中,不同的设备有不同的等待队列,对于tcp_poll来说,其等待队列是sk->sk_sleep(注意把进程挂到等待队列中并不代表进程已经睡眠了)。在设备收到一条消息(网络设备)或填写完文件数据(磁盘设备)后,会唤醒设备等待队列上睡眠的进程,这时current便被唤醒了。
(6)poll方法返回时会返回一个描述读写操作是否就绪的mask掩码,根据这个mask掩码给fd_set赋值。
(7)如果遍历完所有的fd,还没有返回一个可读写的mask掩码,则会调用schedule_timeout是调用select的进程(也就是current)进入睡眠。当设备驱动发生自身资源可读写后,会唤醒其等待队列上睡眠的进程。如果超过一定的超时时间(schedule_timeout指定),还是没人唤醒,则调用select的进程会重新被唤醒获得CPU,进而重新遍历fd,判断有没有就绪的fd。
(8)把fd_set从内核空间拷贝到用户空间。
Несколько основных недостатков select:
(1)每次调用select,都需要把fd集合从用户态拷贝到内核态,这个开销在fd很多时会很大
(2)同时每次调用select都需要在内核遍历传递进来的所有fd,这个开销在fd很多时也很大
(3)select支持的文件描述符数量太小了,默认是1024
2. Реализация опроса
Реализация poll очень похожа на select, за исключением того, что способ описания набора fd отличается.Poll использует структуру pollfd вместо структуры fd_set для select, а остальные аналогичны.
Для анализа реализации select и poll вы можете обратиться к следующим сообщениям в блоге:
select(poll) анализ реализации системного вызова (1)
select(poll) анализ реализации системного вызова (2)
select(poll) анализ реализации системного вызова (3)
Анализ принципа реализации функции выбора
3. Эполл
Поскольку epoll является улучшением по сравнению с select и poll, он должен быть в состоянии избежать трех вышеупомянутых недостатков. Как решается epoll? Перед этим давайте взглянем на разницу в вызывающем интерфейсе между epoll и select и poll.И select, и poll предоставляют только одну функцию — функцию select или poll. И epoll предоставляет три функции: epoll_create, epoll_ctl и epoll_wait, epoll_create — для создания дескриптора epoll, epoll_ctl — для регистрации типа события, которое нужно отслеживать, epoll_wait — для ожидания генерации события.
Что касается первого недостатка, решение epoll находится в функции epoll_ctl. Каждый раз, когда в дескрипторе epoll регистрируется новое событие (укажите EPOLL_CTL_ADD в epoll_ctl), все fd будут копироваться в ядро, а не повторяться во время epoll_wait. epoll гарантирует, что каждый fd будет скопирован только один раз за весь процесс.
Что касается второго недостатка, то решение epoll не похоже на select или poll, которые каждый раз добавляют ток в очередь ожидания устройства, соответствующую fd, а только один раз вешают ток во время epoll_ctl (это время существенно) и предусматривают каждый Каждый fd указывает функцию обратного вызова.Когда устройство будет готово и разбудит ожидающих в очереди ожидания, будет вызвана эта функция обратного вызова, и эта функция обратного вызова добавит готовый fd в список готовых). Задача epoll_wait на самом деле состоит в том, чтобы проверить, есть ли готовый fd в этом готовом списке (используйте schedule_timeout(), чтобы некоторое время приостановить работу и какое-то время оценить эффект, что аналогично шагу 7 в реализации select).
Что касается третьего недостатка, у epoll нет этого ограничения.Верхний предел поддерживаемого FD — это максимальное количество открытых файлов.Это число, как правило, намного больше, чем 2048. Например, на машине с 1 ГБ памяти это около 100 000. Конкретное число Вы можете просмотреть в кате /proc/sys/fs/file-max.Вообще говоря, это число во многом связано с системной памятью.
Суммировать:
(1) Реализация select, poll должна непрерывно опрашивать все наборы fd самостоятельно, пока устройство не будет готово, в течение которого оно может чередоваться между спящим режимом и пробуждением несколько раз. На самом деле, epoll также должен вызывать epoll_wait для непрерывного опроса списка готовности, во время которого он может чередоваться между режимом сна и пробуждением много раз, но когда устройство будет готово, вызвать callback-функцию, поместить готовый fd в список готовых, просыпаться и засыпать в процессе epoll_wait. Несмотря на то, что как sleep, так и alter, select и poll должны пройти через всю коллекцию fd, когда «бодрствуют», а epoll нужно только оценить, пуст ли список готовых файлов, когда «бодрствует», что экономит много процессорного времени. Это улучшение производительности, вызванное механизмом обратного вызова.
(2) Выберите, poll каждый вызов должен один раз скопировать набор fd из пользовательского режима в режим ядра и один раз повесить текущий в очередь ожидания устройства, в то время как epoll нужно скопировать только один раз и повесить текущий в очередь ожидания. (в начале epoll_wait обратите внимание, что очередь ожидания здесь — это не очередь ожидания устройства, а очередь ожидания, определенная внутри epoll). Это также может сэкономить много затрат.
Использованная литература:
выбрать анализ реализации исходного кода
выбор, опрос, анализ реализации epoll — в сочетании с исходным кодом ядра
Краткое изложение использования select, poll и epoll
Полный пример исходного кода на языке c с использованием epoll