Node.js
Eventloop
Поиск…
Вступление
В этой статье мы обсудим, как появилась концепция Eventloop и как ее можно использовать для высокопроизводительных серверов и приложений, управляемых событиями, таких как графические интерфейсы.
Как эволюционировала концепция цикла событий.
Eventloop в псевдокоде
Цикл событий представляет собой цикл, ожидающий событий, а затем реагирует на эти события
while true:
wait for something to happen
react to whatever happened
Пример однопоточного HTTP-сервера без цикла события
while true:
socket = wait for the next TCP connection
read the HTTP request headers from (socket)
file_contents = fetch the requested file from disk
write the HTTP response headers to (socket)
write the (file_contents) to (socket)
close(socket)
Вот простая форма HTTP-сервера, которая представляет собой однопоточный, но не цикл событий. Проблема здесь в том, что он ждет, пока каждый запрос не будет закончен, прежде чем начинать обработку следующего. Если для чтения заголовков HTTP-запросов или для извлечения файла с диска требуется некоторое время, мы сможем начать обработку следующего запроса, пока мы ждем его завершения.
Наиболее распространенное решение - сделать программу многопоточной.
Пример многопоточного HTTP-сервера без цикла события
function handle_connection(socket):
read the HTTP request headers from (socket)
file_contents = fetch the requested file from disk
write the HTTP response headers to (socket)
write the (file_contents) to (socket)
close(socket)
while true:
socket = wait for the next TCP connection
spawn a new thread doing handle_connection(socket)
Теперь мы сделали наш небольшой HTTP-сервер многопоточным. Таким образом, мы можем сразу перейти к следующему запросу, поскольку текущий запрос выполняется в фоновом потоке. Многие серверы, включая Apache, используют этот подход.
Но это не идеально. Одно ограничение состоит в том, что вы можете создавать только столько потоков. Для рабочих нагрузок, где у вас огромное количество подключений, но каждое подключение требует только внимания каждый раз, многопоточная модель не будет работать очень хорошо. Решением для этих случаев является использование цикла событий:
Пример HTTP-сервера с циклом события
while true:
event = wait for the next event to happen
if (event.type == NEW_TCP_CONNECTION):
conn = new Connection
conn.socket = event.socket
start reading HTTP request headers from (conn.socket) with userdata = (conn)
else if (event.type == FINISHED_READING_FROM_SOCKET):
conn = event.userdata
start fetching the requested file from disk with userdata = (conn)
else if (event.type == FINISHED_READING_FROM_DISK):
conn = event.userdata
conn.file_contents = the data we fetched from disk
conn.current_state = "writing headers"
start writing the HTTP response headers to (conn.socket) with userdata = (conn)
else if (event.type == FINISHED_WRITING_TO_SOCKET):
conn = event.userdata
if (conn.current_state == "writing headers"):
conn.current_state = "writing file contents"
start writing (conn.file_contents) to (conn.socket) with userdata = (conn)
else if (conn.current_state == "writing file contents"):
close(conn.socket)
Надеюсь, этот псевдокод понятен. Вот что происходит: мы ждем, когда что-то случится. Всякий раз, когда создается новое соединение или существующее соединение требует нашего внимания, мы решаем его, а затем возвращаемся к ожиданию. Таким образом, мы хорошо себя чувствуем, когда есть много соединений, и каждый из них редко требует внимания.
В реальном приложении (не псевдокоде), запущенном в Linux, часть «ожидание следующего события» будет реализована путем вызова системного вызова poll () или epoll (). «Начало чтения / записи чего-то в сокет» будет реализовано путем вызова системных вызовов recv () или send () в неблокирующем режиме.
Ссылка:
[1]. «Как работает цикл событий?» [Онлайн]. Доступно: https://www.quora.com/How-does-an-event-loop-work