事件循环的概念是如何演变的

在伪代码中的 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