오늘 Unity에 대한 강의 중 하나에서 사용자가 버튼을 눌렀는지 확인하면 모든 프레임을 확인하여 플레이어 위치를 업데이트하는 것에 대해 논의했습니다. 누군가는 이것이 비효율적이라고 말하면서 대신 이벤트 리스너를 사용해야합니다.
내 질문은 프로그래밍 언어 또는 적용되는 상황에 관계없이 이벤트 리스너가 어떻게 작동합니까?
내 직감은 이벤트 리스너가 이벤트가 발생했는지 지속적으로 확인한다고 가정합니다. 즉, 시나리오에서는 이벤트가 발생했는지 모든 프레임을 확인하는 것과 다르지 않습니다.
수업 토론을 바탕으로 이벤트 리스너가 다른 방식으로 작동하는 것 같습니다.
이벤트 리스너는 어떻게 작동합니까?
답변
사용자가 제공 한 폴링 예제 (버튼마다 프레임이 확인되는 경우)와 달리 이벤트 리스너는 버튼이 눌 렸는지 확인하지 않습니다. 대신 버튼을 누를 때 호출됩니다.
아마도 “이벤트 리스너”라는 용어가 당신을 던지고있을 것입니다. 이 용어는 “리스너 (listener)”가 실제로 무언가를하지 않을 때들을 수있는 무언가를 적극적으로하고 있음을 시사합니다. “리스너 (listener)”는 이벤트에 등록 된 함수 또는 메소드 일뿐입니다. 이벤트가 발생하면 리스너 메소드 ( “이벤트 핸들러”)가 호출됩니다.
이벤트 패턴의 장점은 실제로 버튼을 누를 때까지 비용이 들지 않는다는 것입니다. 이벤트는 이벤트를 발생시키기 위해 실행중인 코드를 잠깐 선점하는 “하드웨어 인터럽트”에서 발생하기 때문에 모니터링하지 않고도 이러한 방식으로 처리 할 수 있습니다.
일부 UI 및 게임 프레임 워크는 “메시지 루프”라는 것을 사용합니다. “메시지 루프”는 나중에 (보통 짧은 기간) 실행을 위해 이벤트를 큐에 대기시킵니다. 그러나 해당 이벤트를 먼저 메시지 루프로 가져 오려면 하드웨어 인터럽트가 필요합니다.
답변
웹 페이지 (정보 전송을 시작하는 사람)를 끊임없이 새로 고치지 않고 전자 메일 뉴스 레터 구독 (자신이 보낸 사람이 전송을 시작한 업데이트를 받도록 등록하는 이벤트)과 유사한 이벤트 리스너입니다.
이벤트 시스템은 등록자 목록을 관리하는 이벤트 오브젝트를 사용하여 구현됩니다. 관심있는 객체 ( 구독자 , 리스너 , 델리게이트 등)는 이벤트에 자신을 구독하는 메소드를 호출하여 이벤트에 대한 알림을 받도록 자신을 구독 할 수 있으며, 이로 인해 이벤트가 목록에 추가됩니다. 이벤트가 될 때마다 해고 (용어도 포함 할 수 있습니다 : 전화 , 트리거 , 호출 , 실행 등)들이 이해할 필요가 문맥 어떤 정보를 함께 전달하는 이벤트를 알리고, 그것은 가입자의 각각에 적절한 방법을 호출 어떻게 된 거예요.
답변
짧고 불만족스러운 대답은 응용 프로그램이 신호 (이벤트)를 수신하고 루틴이 해당 시점에서만 호출된다는 것입니다.
더 긴 설명은 조금 더 복잡합니다.
클라이언트 이벤트는 어디서 시작됩니까?
각 최신 응용 프로그램 † 에는 일반적으로 반 숨겨진 내부 “이벤트 루프”가 있으며이를 수신해야하는 올바른 구성 요소로 이벤트를 전달합니다. 예를 들어, “click”이벤트는 현재 마우스 좌표에서 표면이 보이는 버튼으로 전송됩니다. 이것은 가장 간단한 수준입니다. 실제로 OS는 일부 이벤트 및 일부 구성 요소가 메시지를 직접 수신하기 때문에 이러한 디스패치를 많이 수행합니다.
응용 프로그램 이벤트는 어디에서 발생합니까?
운영 체제는 이벤트가 발생할 때 이벤트를 전달합니다. 그들은 그들 자신의 운전자에 의해 통지를 받아 반응 적으로 그렇게합니다.
드라이버는 어떻게 이벤트를 생성합니까?
저는 전문가는 아니지만 일부 사람들은 CPU 인터럽트를 사용합니다. 새로운 데이터를 사용할 수있을 때 제어하는 하드웨어가 CPU에서 핀을 발생시킵니다. CPU는 들어오는 데이터를 처리하는 드라이버를 시작하여 결국 (큐의) 이벤트를 전달한 다음 제어를 OS로 되돌립니다.
보시다시피, 응용 프로그램이 실제로 항상 실행되지는 않습니다. 이벤트가 발생할 때 OS (Sorta)에 의해 시작되는 절차는 많지만 나머지 시간에는 아무것도하지 않습니다.
† 눈에 띄는 예외가 있습니다. 예를 들어 게임이 다르게 작동하는 게임
답변
술어
-
event : 일어날 수있는 일.
-
이벤트 발생 : 특정 이벤트 발생; 이벤트가 발생합니다.
-
이벤트 리스너 : 이벤트 발생을 찾는 것.
-
event handler : 이벤트 리스너가 이벤트 발생을 감지 할 때 발생하는 것입니다.
-
event subscriber : 이벤트 핸들러가 호출해야하는 응답.
이러한 정의는 구현에 의존하지 않으므로 다른 방식으로 구현할 수 있습니다.
이러한 용어 중 일부는 일반적으로 사용자가 서로 구별 할 필요가 없기 때문에 동의어로 오인됩니다.
일반적인 시나리오
-
프로그래밍 논리 이벤트.
-
이벤트는 몇 가지 방법이 호출 될 때입니다.
-
이벤트 발사는 그 방법에 대한 특정 호출입니다.
-
이벤트 리스너는 이벤트 핸들러를 호출 각 이벤트 발사에라고 이벤트 방법에 훅입니다.
-
이벤트 핸들러는 이벤트 가입자의 컬렉션을 호출합니다.
-
이벤트 가입자 는 이벤트 발생에 대한 응답으로 시스템이 의미하는 모든 행동을 수행합니다.
-
-
외부 행사.
-
이 사건 은 관측 가능한 것으로 추론 할 수있는 외부 사건입니다.
-
이벤트 소성 그 외부 일어나는 발생한 것으로 인식 할 수있는 경우이다.
-
이벤트 리스너는 어떻게 든 자주 폴링에 의해, 이벤트 발사를 감지 관찰 (들), 다음이 발사 이벤트를 감지하면 이벤트 핸들러를 호출합니다.
-
이벤트 핸들러는 이벤트 가입자의 컬렉션을 호출합니다.
-
이벤트 가입자 는 이벤트 발생에 대한 응답으로 시스템이 의미하는 모든 행동을 수행합니다.
-
폴링 vs. 이벤트의 발사 메커니즘에 후크 삽입
다른 사람들의 요점은 종종 폴링이 필요하지 않다는 것입니다. 이벤트 발생시 이벤트 핸들러가 자동으로 이벤트 핸들러를 호출하도록하여 이벤트 리스너를 구현할 수 있기 때문입니다. 이는 이벤트가 시스템 레벨 발생 일 때이를 구현하는 가장 효율적인 방법입니다.
우체국 직원이 문을 두드리고 직접 우편물을 건네주는 경우 매일 우편함에서 우편물을 확인하지 않아도됩니다.
그러나 이벤트 리스너는 폴링을 통해 작동 할 수도 있습니다. 폴링이 반드시 특정 값이나 다른 관찰 가능한 값을 확인할 필요는 없습니다. 더 복잡 할 수 있습니다. 그러나 전반적으로 폴링의 요점은 일부 이벤트가 발생했을 때 응답 할 수 있도록 추론하는 것입니다.
유추하여 우편 배달원이 우편물을 보내기 만하면 우편함을 매일 확인해야합니다. 우체국 직원에게 문을 두드리라 고 지시 할 수 있다면이 폴링 작업을 수행 할 필요는 없지만 종종 가능하지는 않습니다.
연쇄 이벤트 로직
많은 프로그래밍 언어에서 키보드의 키를 누르거나 특정 시간에 방금 호출되는 이벤트를 작성할 수 있습니다. 외부 이벤트이지만 폴링 할 필요는 없습니다. 왜?
운영 체제가 사용자를 폴링하기 때문입니다. 예를 들어, Windows는 키보드 상태 변경과 같은 것을 확인하고이를 감지하면 이벤트 가입자를 호출합니다. 따라서 키보드 프레스 이벤트에 가입하면 실제로는 폴링 이벤트에 대한 가입자 자체 인 이벤트에 가입하게됩니다.
유사하게, 당신이 아파트 단지에 살고 있고 우체국 직원이 공동 우편 영수증 지역으로 우편물을 가져옵니다. 그런 다음 운영 체제와 유사한 작업자가 모든 사람을 위해 해당 메일을 확인하여 무언가를받은 사람들의 아파트로 메일을 배달 할 수 있습니다. 이렇게하면 다른 모든 사람이 메일 수신 영역을 폴링해야하는 번거 로움을 덜 수 있습니다.
내 직감은 이벤트 리스너가 이벤트가 발생했는지 지속적으로 확인한다고 가정합니다. 즉, 시나리오에서는 이벤트가 발생했는지 모든 프레임을 확인하는 것과 다르지 않습니다.
수업 토론을 바탕으로 이벤트 리스너가 다른 방식으로 작동하는 것 같습니다.
이벤트 리스너는 어떻게 작동합니까?
의심 한대로 이벤트 는 폴링을 통해 작동 할 수 있습니다 . 그리고 이벤트가 키보드 키를 누르는 것과 같이 외부에서 발생하는 문제와 관련이있는 경우 어느 시점에서 폴링이 발생해야합니다.
이벤트에 반드시 폴링이 필요하지는 않습니다. 예를 들어, 이벤트가 단추를 눌렀을 때 발생하는 경우 해당 단추의 이벤트 리스너는 마우스 클릭이 단추를 누르는 것으로 판단 될 때 GUI 프레임 워크가 호출 할 수있는 메소드입니다. 이 경우 마우스 클릭이 감지 되려면 여전히 폴링이 발생해야하지만 마우스 리스너는 이벤트 체인을 통해 기본 폴링 메커니즘에 연결된보다 수동적 인 요소입니다.
업데이트 : 저수준 하드웨어 폴링
USB 장치 및 기타 최신 통신 프로토콜에는 상호 작용을위한 다소 매혹적인 네트워킹과 유사한 프로토콜 세트가있어 키보드 및 마우스를 포함한 I / O 장치가 임시 토폴로지 에 참여할 수 있습니다.
흥미롭게도 ” 인터럽트 “는 매우 필수적인 동기식이므로 임시 네트워킹 토폴로지를 처리하지 않습니다 . 이 문제를 해결하기 위해 ” 인터럽트 “는 ” 인터럽트 트랜잭션 “ (USB 컨텍스트) 또는 ” 메시지 신호 인터럽트 “ (PCI 컨텍스트 ) 라고하는 비동기 우선 순위가 높은 패킷으로 일반화되었습니다 . 이 프로토콜은 USB 사양에 설명되어 있습니다.
– ” 그림 8-31. “범용 직렬 버스 사양, 개정 2.0 “의 벌크 / 제어 / 인터럽트 OUT 트랜잭션 호스트 상태 머신 ” -222 페이지; PDF-250 페이지 (2000-04-27)
요점은 I / O 장치 및 통신 구성 요소 (USB 허브 등)가 기본적으로 네트워크 장치처럼 작동하는 것 같습니다. 따라서 포트를 폴링해야하는 메시지를 보냅니다. 이를 통해 전용 하드웨어 라인이 필요하지 않습니다.
윈도우와 같은 운영 체제가 폴링 과정 자체를 처리하는 것, 예에 설명 된대로 에 대한 MSDN 문서 USB_ENDPOINT_DESCRIPTOR
의 제어하는 방법에 대해 설명합니다 얼마나 자주 윈도우 여론 조사 인터럽트 / 등시성 메시지에 대한 USB 호스트 컨트롤러 :
이
bInterval
값에는 인터럽트 및 등시성 엔드 포인트에 대한 폴링 간격이 포함됩니다. 다른 유형의 엔드 포인트의 경우이 값을 무시해야합니다. 이 값은 장치의 펌웨어 구성을 반영합니다. 드라이버는 변경할 수 없습니다.폴링 간격은 장치 속도 및 호스트 컨트롤러 유형과 함께 드라이버가 인터럽트 또는 등시 전송을 시작해야하는 빈도를 결정합니다. 의 값은
bInterval
고정 된 시간 을 나타내지 않습니다. 상대 값이며 실제 폴링 주파수는 장치와 USB 호스트 컨트롤러가 저속, 전속 또는 고속으로 작동하는지에 따라 달라집니다.– “USB_ENDPOINT_DESCRIPTOR 구조” , Microsoft 하드웨어 개발 센터
DisplayPort 와 같은 최신 모니터 연결 프로토콜도 동일한 것으로 보입니다.
멀티 스트림 전송 (MST)
DisplayPort 버전 1.2에 추가 된 MST (Multi-Stream Transport)
- Ver.1.1a에서는 SST (Single-Stream Transport) 만 사용할 수있었습니다.
MST는 단일 커넥터를 통해 여러 A / V 스트림을 전송합니다
최대 63 개 스트림; “레인 당 스트림”이 아님
- 전송 된 스트림들 사이에는 동기 성이 없다. 하나의 스트림은 블랭킹 기간에 있고 다른 스트림은 그렇지 않습니다.
연결 지향 운송
스트림 전송을 시작하기 전에 AUX CH를 통한 메시지 트랜잭션을 통해 설정된 스트림 소스에서 대상 스트림 싱크로의 경로
나머지 스트림에 영향을주지 않고 스트림 추가 / 삭제
– 슬라이드 # 14를 “DisplayPortTM ver.1.2 도서 개요” (2010-12-06)
이 추상화는 한 연결에서 3 개의 모니터를 실행하는 것과 같은 몇 가지 깔끔한 기능을 허용합니다.
또한 DisplayPort Multi-Stream Transport를 사용하면 3 개 이상의 장치를 함께 연결할 수 있지만 반대의 “소비자”지향 구성으로 단일 출력 포트에서 여러 디스플레이를 동시에 구동 할 수 있습니다.
– “DisplayPort” , Wikipedia
개념적으로,이 점에서 벗어나는 요점은 폴링 메커니즘이보다 일반화 된 직렬 통신을 허용한다는 것입니다. 이는보다 일반적인 기능을 원할 때 매우 좋습니다. 따라서 하드웨어와 OS는 논리 시스템에 대해 많은 폴링을 수행합니다. 그러면 이벤트를 구독하는 소비자는 자체 폴링 / 메시지 전달 프로토콜을 작성할 필요없이 하위 수준 시스템에서 처리하는 세부 정보를 즐길 수 있습니다.
궁극적으로 키 누름과 같은 이벤트는 소프트웨어 수준의 필수 이벤트 발생 메커니즘에 도달하기 전에 다소 흥미로운 일련의 이벤트를 거치는 것으로 보입니다.
답변
풀 대 푸시
이벤트가 발생했는지 또는 특정 상태에 도달했는지 확인하는 두 가지 주요 전략이 있습니다. 예를 들어 중요한 배달을 기다리는 것을 상상해보십시오.
- 당기기 : 10 분마다 사서함으로 내려가 배달되었는지 확인합니다.
- 푸시 : 배달원에게 배달 할 때 전화를 걸도록 지시합니다.
풀 (또한 폴링이라고도 함) 접근 방식은 간단하다 : 당신이 어떤 특별한 기능없이 구현할 수 있습니다. 반면에, 표시 할 항목이없는 추가 검사를 수행 할 위험이 있기 때문에 종종 효율성이 떨어집니다.
반면에, 푸쉬 접근법은 일반적으로 더 효율적입니다. 코드는 할 일이있을 때만 실행됩니다. 반면에 리스너 / 관찰자 / 콜백 1 등록을위한 메커니즘이 필요합니다 .
1 우체부 직원은 불행히도 그러한 메커니즘이 부족합니다.
답변
구체적으로 화합에 대하여-매 프레임마다 폴링하는 것 외에 플레이어의 입력을 확인하는 다른 방법은 없습니다. 이벤트 리스너를 작성하려면 여전히 폴링을 수행하기 위해 “이벤트 시스템”또는 “이벤트 관리자”와 같은 오브젝트가 필요하므로 문제점을 다른 클래스로만 푸시합니다.
이벤트 관리자가 있으면 한 프레임마다 입력을 폴링하는 클래스가 하나 뿐이지 만,이 클래스는 리스너를 반복하고 호출해야하기 때문에 성능에 이점이 없습니다. 디자인 (예 : 청취자가 몇 명이고 플레이어가 입력을 얼마나 자주 사용하는지)과 같이 실제로 비용이 더 많이들 수 있습니다.
이 모든 것 외에도 골든 규칙을 기억하십시오. 조기 최적화는 모든 악의 근원이며 , 특히 비디오 게임에서 특히 그렇습니다. 각 프레임의 렌더링 프로세스가 너무 비싸서 이와 같은 작은 스크립트 최적화는 완전히 중요하지 않습니다.
답변
버튼 누름 또는 타이머 오버플로 또는 메시지 도착과 같은 이벤트를 처리하는 OS / 프레임 워크를 지원하지 않는 한 폴링을 사용하여이 이벤트 리스너 패턴을 구현해야합니다 (어딘가 아래).
그러나 바로 성능상의 이점이 없기 때문에이 디자인 패턴에서 벗어나지 마십시오. 이벤트 처리에 대한 기본 지원 여부에 관계없이 사용해야하는 이유는 다음과 같습니다.
- 코드가 깨끗하고 격리 된 것처럼 보입니다 (물론 올바르게 구현 된 경우)
- 이벤트 핸들러를 기반으로하는 코드는 변경 사항을 더 잘 유지합니다 (일반적으로 일부 이벤트 핸들러 만 수정하므로)
- 기본 이벤트 지원을 통해 플랫폼으로 이동하는 경우 기존 이벤트 핸들러를 재사용하고 폴링 코드를 제거 할 수 있습니다.
결론-토론에 참여하여 운이 좋았으며 설문 조사에 대한 대안을 배웠습니다. 이 개념을 실제로 적용 할 수있는 기회를 찾으면 코드가 얼마나 우아 할 수 있는지 감사하게 생각할 것입니다.