이벤트 루프는 폴링이 최적화 된 for / while 루프입니까?


55

이벤트 루프가 무엇인지 이해하려고합니다. 종종 이벤트 루프에서 이벤트가 발생했다는 알림을받을 때까지 무언가를 수행한다는 설명이 있습니다. 그런 다음 이벤트를 처리하고 이전에하고 있던 작업을 계속 수행합니다.

위의 정의를 예제와 함께 매핑합니다. 이벤트 루프에서 '듣는'서버가 있으며 소켓 연결이 감지되면 데이터를 읽고 표시 한 후 서버가 이전과 같이 청취를 재개 / 시작합니다.


그러나이 사건이 발생하고 우리에게 '그런 식으로'알림을받는 것은 내가 처리해야 할 일입니다. "이벤트 리스너를 등록해야하는 '그런 것만은 아닙니다'"라고 말할 수 있습니다. 그러나 이벤트 리스너는 무엇이지만 어떤 이유로 든 반환되지 않는 함수입니다. 이벤트가 발생하면 알림을 기다리는 자체 루프에 있습니까? 이벤트 리스너도 이벤트 리스너를 등록해야합니까? 어디서 끝나요?


이벤트는 작업하기에 좋은 추상화이지만 추상화 일뿐입니다. 결국 폴링은 불가피하다고 생각합니다. 아마도 우리는 코드에서 그것을하지 않고 있지만 낮은 수준 (프로그래밍 언어 구현 또는 OS)이 우리를 위해하고 있습니다.

기본적으로 다음과 같은 의사 코드로 내려와 충분히 낮은 곳에서 실행되므로 바쁜 대기를하지 않습니다.

while(True):
    do stuff
    check if event has happened (poll)
    do other stuff

이것이 전체 아이디어에 대한 나의 이해이며, 이것이 올바른지 듣고 싶습니다. 나는 전체 아이디어가 근본적으로 잘못되었다는 것을 받아들이고 있으며,이 경우 올바른 설명을 원합니다.


3
이벤트 시스템은 관찰자 패턴의 구현입니다 . 패턴을 이해하면 사건에 대한 이해가 강화되어야합니다. 폴링이 필요하지 않습니다.
Steven Evers

1
언어 구성이 추상적이더라도 궁극적으로 그렇습니다.
GrandmasterB

@SteveEvers 위키 링크에서. 은 어떻게되어 EventSource있지 폴링 키보드 입력하면거야?
TheMeaningfulEngineer

@ Alan : 그것은 무엇이든 할 수 있지만 키보드 입력을 위해 특별히 키보드 이벤트를 수신하는 것으로 응용 프로그램을 등록하는 API가 있습니다. 그런 다음 폴링을 사용하지 않고 이벤트 소스로 사용할 수 있습니다. 물론, 충분히 내려 가면 USB는 항상 폴링이지만 인터럽트 구동 PS / 2 키보드를 사용한다고 가정하고 폴링이 0 인 이벤트를 기반으로 키보드 입력 스택을 가지고 있다고 가정 해 봅시다.
Phoshi

나는 몇 년 이후이 질문을했지만 왜 물어 보지 않았는지 알 수 없습니다. 감사합니다. @Karl Bielefeldt가 저를 깨달았습니다.
0xc0de 5

답변:


54

준비된 이벤트가 없으면 대부분의 이벤트 루프가 일시 중단됩니다. 즉, 운영 체제는 이벤트가 발생할 때까지 작업 실행 시간을 제공하지 않습니다.

이벤트가 눌러지고 있다고 가정하십시오. 운영 체제에서 키 누르기를 확인하는 루프가 있는지 물어볼 수 있습니다. 내 대답은 아니오 야. 누른 키는 인터럽트를 생성하며 ,이 인터럽트 는 하드웨어에 의해 비동기 적으로 처리됩니다. 타이머, 마우스 움직임, 패킷 도착 등에 대해서도 마찬가지입니다.

실제로 대부분의 운영 체제에서 이벤트 폴링은 추상화입니다. 하드웨어 및 OS는 이벤트를 비동기 적으로 처리하고 애플리케이션이 폴링 할 수있는 큐에 넣습니다. 임베디드 시스템의 하드웨어 수준에서만 진정한 폴링을 볼 수 있으며 항상 그런 것은 아닙니다.


4
전선의 전압 변화를 방해하지 않습니까? 이벤트 자체를 트리거 할 수 있습니까? 아니면 전압 값을 위해 핀을 폴링해야합니까?
TheMeaningfulEngineer

8
이벤트 자체를 트리거 할 수 있습니다. 프로세서는 그런 식으로 설계되었습니다. 실제로 인터럽트에 의해 프로세서가 절전 모드에서 해제 될 수 있습니다.
Karl Bielefeldt

2
나는 진술과 혼동된다 Most event loops will block. 이것이 "스레드 사용과 반대되는 이벤트 루프 패러다임에 어떻게 맞지 않습니까?"
TheMeaningfulEngineer

1
GTK +와 같은 라이브러리에 대한 이벤트 루프를 보면 새로운 이벤트를 확인한 후 루프에서 이벤트 핸들러를 호출하지만 이벤트가없는 경우 세마포어 또는 타이머 등을 차단합니다. 개별 개발자는 빈 이벤트 큐에서 차단하지 않고 널리 사용되는 라이브러리는 모두 차단하는 자체 이벤트 루프를 만듭니다. 그렇지 않으면 이벤트 루프가 너무 비효율적입니다.
Karl Bielefeldt

1
그런 식으로 볼 수는 있지만 응용 프로그램 코드가 아닌 라이브러리 및 / 또는 OS의 멀티 스레딩입니다. 이벤트 루프는 응용 프로그램 개발자를위한 동기화 문제를 추상화합니다.
Karl Bielefeldt

13

이벤트 리스너는 자체 루프를 실행하는 함수가 아니라 첫 번째 주자가 시작 총을 기다리는 릴레이 경주라고 생각합니다. 폴링 대신 이벤트를 사용하는 중요한 이유는 CPU주기에서 더 효율적이기 때문입니다. 왜? 소스 코드가 아닌 하드웨어에서 확인하십시오.

웹 서버를 고려하십시오. 서버가 전화를 걸고 listen()차단하면 코드가 릴레이 러너로 자리 잡고 있습니다. 새 연결의 첫 번째 패킷이 도착하면 운영 체제를 중단하여 네트워크 카드가 경쟁을 시작합니다. OS는 패킷을 잡는 인터럽트 서비스 루틴 (ISR)을 실행합니다. ISR은 배턴을 연결을 설정하는 상위 수준의 루틴으로 전달합니다. 연결이 활성화되면 해당 루틴은 배턴을 listen()로 전달하여 배턴을 코드로 전달합니다. 이 시점에서 연결로 원하는 것을 수행 할 수 있습니다. 우리가 아는 한, 경주마다 각 릴레이 주자가 술집에 갈 수 있습니다. 이벤트 추상화의 강점은 코드가 알거나 신경 쓸 필요가 없다는 것입니다.

일부 운영 체제에는 레이스의 일부를 실행하고 배턴을 건네 준 후 다음 레이스가 시작될 때까지 대기하기 위해 시작점으로 루프백하는 이벤트 처리 코드가 포함됩니다. 그런 의미에서 이벤트 처리는 많은 동시 루프에서 폴링을 최적화합니다. 그러나 프로세스를 시작하는 외부 트리거가 항상 있습니다. 이벤트 리스너는 리턴하지 않는 함수가 아니라 외부 트리거가 실행되기 전에 대기하는 함수입니다. 오히려 :

while(True):
    do stuff
    check if event has happened (poll)
    do other stuff

나는 이것을 다음과 같이 생각한다 :

on(some event):    //I got the baton
     do stuff
     signal the next level up    //Pass the baton

와 사이 signal와 핸들러가 다음에 실행될 때, 개념적으로 실행 또는 루프에는 코드가 없다.


이것은 의미가 있지만 인터럽트를 기다리는 동안 이벤트 루프는 무엇을합니까? 그것이 막히고 있다면, 이벤트 루프와 반대되는 패러다임 인 '멀티 스레드'접근이 아닌가?
TheMeaningfulEngineer

코드에 루프가 있으면 루프 forever: { select(); do stuff; }를 통해 매번 레이스에 다시 들어갑니다. 단일 스레드에서 반복적으로 수행하든 별도의 스레드 또는 프로세서에서 병렬로 수행하든 각 이벤트는 자체 레이스라고 생각합니다. 예를 들어, 웹 브라우저는 최소한 하나의 UI와 다운로드중인 페이지마다 하나씩 별도의 스레드에 여러 이벤트 루프가있는 다중 스레드 프로그램입니다. 코딩 할 때 묻는 질문은 "이벤트를 얼마나 빨리 처리 할 수 ​​있습니까?"입니다. 때때로 대답은 루프, 때로는 스레드, 종종 조합입니다.
cxw

저는 수십 년 동안 이벤트 기반 프로그래밍을 해왔으며이 답변이 매우 혼란 스러웠습니다. 리스너가 작동하려면 이벤트를 기다린 다음 등록 된 모든 리스너로 라우트하는 루프가 있어야합니다. (하드웨어 인터럽트보다는 소프트웨어에 대해 이야기하고 있다고 가정)
Bryan Oakley

8

아니요. "최적화 된 폴링"이 아닙니다. 이벤트 루프는 폴링 대신 인터럽트 구동 I / O를 사용합니다.

while, Until, For 등 루프는 폴링 루프입니다.

"폴링"은 반복적으로 무언가를 확인하는 프로세스입니다. 루프 코드는 지속적으로 실행하고 있기 때문에 때문에 그것은 작은, "꽉"루프는 프로세서가 작업을 전환하고 다른 작업을 수행하기 위해, 약간의 시간이있다. 컴퓨터가 응답하지 않을 때 거의 모든 "멈춤", "멈춤", "잠금"또는 호출하려는 것은 의도하지 않은 폴링 루프에 코드가 표시되는 것입니다. 계측에는 100 % CPU 사용량이 표시됩니다.

인터럽트 구동 이벤트 루프는 폴링 루프보다 훨씬 효율적입니다. 폴링은 CPU 사이클을 매우 낭비 적으로 사용하므로 CPU 사이클을 제거하거나 최소화하기 위해 최선을 다합니다.

그러나 코드 품질을 최적화하기 위해 대부분의 언어는 프로그램 내에서 기능적으로 유사한 목적을 수행하므로 이벤트 처리 명령에 대해 가능한 한 폴링 루프 패러다임을 사용하려고합니다. 따라서, 폴링이 키 누르기 나 다른 것을 기다리는 가장 친숙한 방법이기 때문에, 경험이없는 사람들은 그것을 사용하는 것이 쉽지만 스스로 실행될 수있는 프로그램으로 시작하지만 실행 중에는 아무것도 작동하지 않습니다. 기계를 "인계"했습니다.

다른 답변에서 설명 된 바와 같이, 인터럽트 구동 이벤트 전달에서는 CPU 내에 "플래그"가 설정되고 해당 플래그가 다른 프로세스 (예 : 키보드)에 의해 변경 될 때까지 프로세스가 "일시 중지"(실행되지 않음)됩니다. 사용자가 키를 눌렀을 때 드라이버를 변경). 플래그가 "높은 높이"와 같은 실제 하드웨어 조건 인 경우이를 "인터럽트"또는 "하드웨어 인터럽트"라고합니다. 그러나 대부분은 CPU 또는 주 메모리 (RAM)의 메모리 주소로 구현되며 "세마포어"라고합니다.

세마포어는 소프트웨어 제어 하에서 변경 될 수 있으므로 소프트웨어 프로세스간에 매우 빠르고 간단한 신호 메커니즘을 제공 할 수 있습니다.

그러나 인터럽트는 하드웨어에 의해서만 변경 될 수 있습니다. 가장 보편적으로 사용되는 인터럽트는 내부 클럭 칩에 의해 일정한 간격으로 트리거되는 것입니다. 클럭 인터럽트에 의해 활성화되는 수많은 종류의 소프트웨어 동작 중 하나는 세마포어의 변경입니다.

많이 빼 냈지만 어딘가에서 멈춰야했습니다. 자세한 내용이 필요한지 문의하십시오.


7

일반적으로 대답은 하드웨어, OS 및 제어하지 않는 백그라운드 스레드로 쉽게 볼 수 있습니다. 네트워크 카드는 CPU에 알리기 위해 인터럽트발생 시키는 일부 데이터를 수신 합니다. OS의 인터럽트 핸들러가이를 처리합니다. 그런 다음 제어하지 않는 백그라운드 스레드 (이벤트를 등록하여 작성하고 이벤트를 등록한 이후로 잠자기 상태)는 이벤트 처리의 일부로 OS에 의해 깨어나고 이벤트 핸들러를 실행합니다.


7

나는 지금까지 본 다른 모든 답변에 반대하고 "예" 라고 말할 것 입니다. 다른 답변이 너무 복잡하다고 생각합니다. 개념적 관점에서 모든 이벤트 루프는 기본적으로 다음과 같습니다.

while <the_program_is_running> {
    event=wait_for_next_event()
    process_event(event)
}

처음으로 이벤트 루프를 이해하려는 경우 간단한 루프로 생각하면 해가되지 않습니다. 일부 기본 프레임 워크는 OS가 이벤트를 전달하기를 기다린 다음 이벤트를 하나 이상의 핸들러로 라우팅 한 후 다음 이벤트를 기다리는 등의 작업을 수행합니다. 이것이 실제로 애플리케이션 소프트웨어 관점에서 볼 수있는 전부입니다.


1
간단 해 +1. 그러나 "대기"에 중점을 둡니다. 이 코드의 실행은 루프의 첫 번째 줄에서 중지되며 이벤트가 발생할 때까지 계속되지 않습니다. 이는 이벤트가 발생할 때까지 반복적으로 이벤트를 확인하는 사용중인 폴링 루프와 다릅니다.
Tom Panning

1

모든 이벤트 트리거가 루프에서 처리되는 것은 아닙니다. 자주 이벤트 엔진을 작성하는 방법은 다음과 같습니다.

interface Listener {
    void handle (EventInfo info);
}

List<Listener> registeredListeners

void triggerEvent (EventInfo info) {
    foreach (listener in registeredListeners) { // Memo 1
        listener.handle(info) // the handling may or may not be synchronous... your choice
    }
}

void somethingThatTriggersAnEvent () {
    blah
    blah
    blah
    triggerEvent(someGeneratedEventInfo)
    more blah
}

메모 1이 루프에 있지만 루프는 각 리스너에게 알리기위한 것입니다. 이벤트 트리거 자체가 반드시 루프에있는 것은 아닙니다.

이론적으로 OS 수준의 키 이벤트는 동일한 기술을 사용할 수 있습니다 (OS가 일종의 registerListenerAPI를 노출하는 경우 폴링을 자주 생각한다고 생각하지만 여기서는 추측하고 있습니다) .

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.