development

기본 이벤트 루프를 어떻게 구현 하시겠습니까?

big-blog 2021. 1. 6. 20:45
반응형

기본 이벤트 루프를 어떻게 구현 하시겠습니까?


GUI 툴킷으로 작업 한 경우 모든 작업이 완료된 후 실행되어야하는 이벤트 루프 / 메인 루프가 있으며 애플리케이션이 활성 상태를 유지하고 다른 이벤트에 응답한다는 것을 알고 있습니다. 예를 들어 Qt의 경우 main ()에서 다음을 수행합니다.

int main() {
    QApplication app(argc, argv);
    // init code
    return app.exec();
}

이 경우 app.exec ()는 애플리케이션의 메인 루프입니다.

이러한 종류의 루프를 구현하는 확실한 방법은 다음과 같습니다.

void exec() {
    while (1) {
        process_events(); // create a thread for each new event (possibly?)
    }
}

그러나 이것은 CPU를 100 %로 제한하고 실질적으로 쓸모가 없습니다. 이제 CPU를 완전히 먹지 않고 반응하는 이벤트 루프를 어떻게 구현할 수 있습니까?

답변은 Python 및 / 또는 C ++로 높이 평가됩니다. 감사.

각주 : 학습을 위해 자체 신호 / 슬롯을 구현하고이를 사용하여 사용자 지정 이벤트 (예 :)를 생성합니다 go_forward_event(steps). 그러나 시스템 이벤트를 수동으로 사용하는 방법을 알고 있다면 그것에 대해서도 알고 싶습니다.


나는 똑같은 것에 대해 많이 궁금해했습니다!

GUI 메인 루프는 의사 코드에서 다음과 같습니다.

void App::exec() {
    for(;;) {
        vector<Waitable> waitables;
        waitables.push_back(m_networkSocket);
        waitables.push_back(m_xConnection);
        waitables.push_back(m_globalTimer);
        Waitable* whatHappened = System::waitOnAll(waitables);
        switch(whatHappened) {
            case &m_networkSocket: readAndDispatchNetworkEvent(); break;
            case &m_xConnection: readAndDispatchGuiEvent(); break;
            case &m_globalTimer: readAndDispatchTimerEvent(); break;
        }
    }
}

"대기 가능"이란 무엇입니까? 음, 시스템에 따라 다릅니다. UNIX에서는 "파일 설명자"라고하며 "waitOnAll"은 :: select 시스템 호출입니다. 소위 vector<Waitable>A는 ::fd_setUNIX에서, 그리고 "whatHappened"실제로 통해 조회됩니다 FD_ISSET. 실제 대기 가능 핸들은 다양한 방법으로 획득됩니다. 예를 들어 m_xConnection:: XConnectionNumber ()에서 가져올 수 있습니다. X11은 또한이를위한 높은 수준의 이식 가능한 API-:: XNextEvent ()-를 제공하지만이를 사용한다면 여러 이벤트 소스를 동시에 기다릴 수 없습니다 .

차단은 어떻게 작동합니까? "waitOnAll"은 프로세스를 "휴면 목록"에 올리도록 OS에 지시하는 시스템 호출입니다. 이는 대기 가능 항목 중 하나에서 이벤트가 발생할 때까지 CPU 시간이 주어지지 않음을 의미합니다. 이는 프로세스가 유휴 상태이며 CPU를 0 % 사용함을 의미합니다. 이벤트가 발생하면 프로세스가 잠시 반응 한 다음 유휴 상태로 돌아갑니다. GUI 앱은 거의 모든 시간을 유휴 상태로 보냅니다 .

잠자는 동안 모든 CPU주기는 어떻게됩니까? 의존합니다. 때로는 다른 프로세스가 사용됩니다. 그렇지 않은 경우 OS는 CPU를 바쁜 루프하거나 임시 저전력 모드 등으로 전환합니다.

자세한 내용은 문의 해주세요!


파이썬 :

파이썬에서 이벤트 루프를위한 최상의 구현 인 Twisted 리액터 의 구현을 볼 수 있습니다 . Twisted의 리액터는 인터페이스의 구현이며 실행할 유형 리액터를 지정할 수 있습니다. select, epoll, kqueue (모두 해당 시스템 호출을 사용하는 ac API 기반), QT 및 GTK 툴킷 기반 리액터도 있습니다.

간단한 구현은 select를 사용하는 것입니다.

#echo server that accepts multiple client connections without forking threads

import select
import socket
import sys

host = ''
port = 50000
backlog = 5
size = 1024
server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server.bind((host,port))
server.listen(backlog)
input = [server,sys.stdin]
running = 1

#the eventloop running
while running:
    inputready,outputready,exceptready = select.select(input,[],[])

    for s in inputready:

        if s == server:
            # handle the server socket
            client, address = server.accept()
            input.append(client)

        elif s == sys.stdin:
            # handle standard input
            junk = sys.stdin.readline()
            running = 0

        else:
            # handle all other sockets
            data = s.recv(size)
            if data:
                s.send(data)
            else:
                s.close()
                input.remove(s)
server.close() 

일반적으로 나는 일종의 계산 세마포로 이것을 할 것입니다 .

  1. 세마포어는 0에서 시작합니다.
  2. 이벤트 루프는 세마포를 기다립니다.
  3. 이벤트가 들어 오면 세마포가 증가합니다.
  4. 이벤트 핸들러는 세마포어를 차단 해제 및 감소시키고 이벤트를 처리합니다.
  5. 모든 이벤트가 처리되면 세마포어는 0이고 이벤트 루프는 다시 차단됩니다.

If you don't want to get that complicated, you could just add a sleep() call in your while loop with a trivially small sleep time. That will cause your message processing thread to yield it's CPU time to other threads. The CPU won't be pegged at 100% any more, but it's still pretty wasteful.


I would use a simple, light-weight messaging library called ZeroMQ (http://www.zeromq.org/). It is an open source library (LGPL). This is a very small library; on my server, the whole project compiles in about 60 seconds.

ZeroMQ will hugely simplify your event-driven code, AND it is also THE most efficient solution in terms of performance. Communicating between threads using ZeroMQ is much faster (in terms of speed) than using semaphores or local UNIX sockets. ZeroMQ also be a 100% portable solution, whereas all the other solutions would tie your code down to a specific operating system.

ReferenceURL : https://stackoverflow.com/questions/658403/how-would-you-implement-a-basic-event-loop

반응형