수색…


소개

이 글에서는 Eventloop의 개념이 어떻게 나타나고 고성능 서버 및 GUI와 같은 이벤트 기반 응용 프로그램에 어떻게 사용될 수 있는지에 대해 논의 할 것입니다.

이벤트 루프의 개념이 어떻게 진화했는지.

의사 코드의 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 () 시스템 호출을 호출하여 구현됩니다. "소켓 읽기 시작 / 쓰기"부분은 non-blocking 모드에서 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