Событийная машина (event loop) позволяет реализовать асинхронную передачу данных для нескольких соединений в рамках одного процесса. Самый быстрый модуль, с которым я имел дело - EV. Суть событийной машины в следующем. Предположим нам надо получить данные от двух серверов. Стандартно это делается так: соединяемся с первым сервером, посылаем запрос, получаем ответ, закрываем соединение, соединяемся со вторым сервером... В случае если соединение установить невозможно, программа будет ожидать до истечения таймаута. Если использовать событийную машину, то алгоритм будет таким: открываем сокет к первому серверу в неблокируемом режиме (не дожидаясь соединения) и создаем функцию-обработчик записи в сокет, открываем сокет ко второму серверу в неблокируемом режиме и создаем функцию-обработчик записи в сокет, создаем таймер для завершения обработки по истечении таймаута (можно задать отдельные таймеры для каждого соединения, по желанию). Запускаем цикл обработки событий. После установления соединения с одним из серверов будет вызвана соответствующая функция-обработчик. Например, для первого сервера. Внутри этой функции мы выполняем запрос к удаленному серверу и создаем функцию-обработчик чтения из сокета, после завершения функции-обработчика записи управление передается обратно в цикл обработки событий (во время выполнения функции-обработчика другие события не обрабатываются, т.к. у нас один поток выполнения). После ответа первого сервера на наш запрос вызывается функция-обработчик для чтения, в которой мы получаем данные из сокета и сохраняем их (или обрабатываем). После получения всех данных закрываем соединение. Функция-обработчик чтения вызывается по мере получения данных от сервера многократно. После получения всех данных от сервера закрываем соденинение. После закрытия всех соединений (или срабатывания таймера) завершаем цикл обработки сообщений.
Сама идея событийной машины проста, но при реализации возникают некоторые сложности. В основном они связаны с передачей данных в функции-обработчики (очень часто это делается при помощи замыканий, что делает код непрозрачным). Дмитрий Карасик сделал попытку упростить использование событийной машины при помощи модуля IO::Lambda, но я, к своему стыду, не сподобился им попользоваться, т.к. все, что было нужно написал на EV. |