サーチ…


前書き

この記事では、Eventloopのコンセプトがどのように浮上し、どのように高性能サーバーやGUIなどのイベント駆動型アプリケーションに使用できるかについて説明します。

イベントループの概念がどのように進化したか

擬似コードによるイベントループ

イベントループは、イベントを待ってからそれらのイベントに反応するループです

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を含む多くのサーバーでは、このアプローチを使用しています。

しかし完璧ではありません。 1つの制限は、非常に多くのスレッドしか生成できないことです。膨大な数の接続があるワークロードでは、接続ごとに注意を払う必要がありますが、マルチスレッドモデルはあまりうまく機能しません。そのような場合の解決方法は、イベントループを使用することです。

イベントループを持つ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



Modified text is an extract of the original Stack Overflow Documentation
ライセンスを受けた CC BY-SA 3.0
所属していない Stack Overflow