Au cours de l’un de mes cours d’aujourd’hui sur Unity, nous avons discuté de la mise à jour de notre position de joueur en vérifiant chaque image si l’utilisateur a un bouton enfoncé. Quelqu'un a dit que cela était inefficace et que nous devrions utiliser un écouteur d'événements à la place.
Ma question est, quel que soit le langage de programmation ou la situation dans laquelle il est appliqué, comment fonctionne un écouteur d'événement?
Mon intuition présumerait que l'écouteur d'événements vérifie en permanence si l'événement a été déclenché, ce qui signifie que dans mon scénario, ce ne serait pas différent de vérifier chaque image si l'événement a été déclenché.
D'après la discussion en classe, il semble que l'écouteur d'événements fonctionne différemment.
Comment fonctionne un écouteur d'événement?
la source
Réponses:
Contrairement à l'exemple d'interrogation que vous avez fourni (où le bouton est coché à chaque image), un écouteur d'événements ne vérifie pas si le bouton est enfoncé. Au lieu de cela, il est appelé lorsque le bouton est enfoncé.
Peut-être que le terme "auditeur d'événement" vous lance. Ce terme suggère que "l'auditeur" fait activement quelque chose pour écouter, alors qu'en fait, il ne fait rien du tout. L '"auditeur" est simplement une fonction ou une méthode abonnée à l'événement. Lorsque l'événement est déclenché, la méthode d'écoute ("gestionnaire d'événements") est appelée.
L'avantage du modèle d'événement est qu'il n'y a aucun coût jusqu'à ce que le bouton soit réellement enfoncé. L'événement peut être traité de cette manière sans surveillance, car il provient de ce que nous appelons une "interruption matérielle", qui empêche brièvement le code en cours d'exécution de déclencher l'événement.
Certaines infrastructures d’interface utilisateur et de jeu utilisent ce qu’on appelle une «boucle de message», qui met les événements en file d’exécution à exécuter ultérieurement (généralement peu de temps), mais vous avez toujours besoin d’une interruption matérielle pour insérer cet événement dans la boucle de message.
la source
Un écouteur d'événement s'apparentant à un abonnement à une lettre d'information par courrier électronique (vous vous inscrivez pour recevoir les mises à jour, dont la transmission est ensuite initiée par l'expéditeur), plutôt que d'actualiser sans fin une page Web (où vous êtes le responsable du transfert de l'information).
Un système d'événements est implémenté à l'aide d'objets Event, qui gèrent une liste d'abonnés. Les objets intéressés (appelés abonnés , auditeurs , délégués , etc.) peuvent s'inscrire eux-mêmes pour être informés d'un événement en appelant une méthode qui s'abonne à l'événement, ce qui a pour effet que l'événement les ajoute à sa liste. Chaque fois que l'événement est déclenché (la terminologie peut également inclure: appelé , déclenché , invoqué , exécuté , etc.), il appelle la méthode appropriée sur chacun des abonnés, pour les informer de l'événement, en transmettant les informations contextuelles qu'ils doivent comprendre. Qu'est-il arrivé.
la source
La réponse courte et non satisfaisante est que l'application reçoit un signal (l'événement) et que la routine n'est appelée qu'à ce moment-là.
L'explication plus longue est un peu plus compliquée.
D'où viennent les événements clients?
Chaque application moderne † possède une "boucle d'événement" interne, généralement semi-cachée, qui distribue les événements aux composants appropriés qui doivent les recevoir. Par exemple, un événement "clic" est envoyé au bouton dont la surface est visible aux coordonnées actuelles de la souris. C'est au niveau le plus simple. En réalité, le système d'exploitation effectue une grande partie de cette répartition, car certains événements et certains composants recevront directement des messages.
D'où viennent les événements d'application?
Les systèmes d'exploitation distribuent les événements au fur et à mesure qu'ils se produisent. Ils le font de manière réactive en étant avertis par leurs propres conducteurs.
Comment les pilotes génèrent-ils des événements?
Je ne suis pas un expert, mais il est certain que certains utilisent des interruptions de la CPU: le matériel qu’ils contrôlent lève une broche sur la CPU lorsque de nouvelles données sont disponibles; la CPU déclenche le pilote qui gère les données entrantes qui génère éventuellement une (file d'attente) d'événements à distribuer, puis redonne le contrôle au système d'exploitation.
Donc, comme vous le voyez, votre application ne fonctionne pas vraiment tout le temps. C'est un tas de procédures qui sont renvoyées par le système d'exploitation (sorta) au fur et à mesure que les événements se produisent, mais ne font rien le reste du temps.
† il y a des exceptions notables, par exemple des jeux pour une fois qui pourraient faire les choses différemment
la source
Terminologie
événement : un type de chose qui peut arriver.
déclenchement d'événement : occurrence spécifique d'un événement; un événement qui se passe.
écouteur d'événement : Quelque chose qui recherche les déclenchements d'événements.
gestionnaire d'événements : quelque chose qui se produit lorsqu'un écouteur d'événements détecte le déclenchement d'un événement.
event subscriber : une réponse que le gestionnaire d'événements est censé appeler.
Ces définitions ne dépendent pas de l'implémentation, elles peuvent donc être implémentées de différentes manières.
Certains de ces termes sont généralement confondus avec des synonymes car les utilisateurs ne sont souvent pas obligés de les distinguer.
Scénarios communs
Programmation d'événements logiques.
L' événement est quand une méthode est appelée.
Un événement déclenchant est un appel particulier à cette méthode.
L' écouteur d'événements est un point d'ancrage dans la méthode d'événement appelée à chaque déclenchement d'événement qui appelle le gestionnaire d'événements.
Le gestionnaire d'événements appelle une collection d'abonnés aux événements.
L' abonné (s) de l'événement effectue (nt) toute action que le système veut dire en réponse à l'occurrence de l'événement.
Événements externes.
L' événement est un événement externe qui peut être déduit d'observables.
Un événement se déclenche lorsque cet événement externe peut être reconnu comme ayant eu lieu.
L' auditeur d'événement détecte en quelque sorte les déclenchements d'événement, souvent en interrogeant le ou les observables, puis appelle le gestionnaire d'événements lors de la détection d'un déclenchement d'événement.
Le gestionnaire d'événements appelle une collection d'abonnés aux événements.
L' abonné (s) de l'événement effectue (nt) toute action que le système veut dire en réponse à l'occurrence de l'événement.
Interrogation ou insertion de crochets dans le mécanisme de déclenchement de l'événement
Les autres soulignent que les sondages ne sont souvent pas nécessaires. En effet, les écouteurs d'événements peuvent être implémentés en faisant en sorte que les déclenchements d'événements appellent automatiquement le gestionnaire d'événements, ce qui est souvent le moyen le plus efficace d'implémenter des tâches lorsque les événements sont des occurrences au niveau du système.
Par analogie, vous n'avez pas besoin de vérifier votre boîte aux lettres chaque jour si le postier frappe à votre porte et vous le remet directement.
Cependant, les écouteurs d'événement peuvent également fonctionner par sondage. L'interrogation ne nécessite pas nécessairement la vérification d'une valeur spécifique ou d'un autre observable; ça peut être plus complexe. Mais, dans l’ensemble, le point d’interrogation consiste à déduire que certains événements se sont produits de manière à pouvoir y répondre.
Par analogie, vous devez vérifier votre boîte aux lettres tous les jours lorsque le postier y dépose simplement du courrier. Vous n’auriez pas à faire ce travail de scrutin si vous pouviez demander au postier de frapper à votre porte, mais ce n’est souvent pas une possibilité.
Chaînage des événements
Dans de nombreux langages de programmation, vous pouvez écrire un événement qui vient d'être appelé lorsqu'une touche du clavier est enfoncée ou à un moment donné. Bien que ces événements soient externes, vous n'avez pas besoin de les interroger. Pourquoi?
C'est parce que le système d'exploitation vous interroge. Par exemple, Windows recherche des éléments tels que les changements d'état du clavier et, s'il en détecte un, il appelle les abonnés aux événements. Ainsi, lorsque vous vous abonnez à un événement de presse au clavier, vous vous abonnez à un événement qui est lui-même un abonné à un événement qui interroge.
Par analogie, disons que vous vivez dans un complexe d'appartements et qu'un employé des postes dépose le courrier dans une zone de réception du courrier commun. Ensuite, un agent semblable à un système d'exploitation peut vérifier ce courrier pour tout le monde, en le distribuant dans les appartements de ceux qui ont reçu quelque chose. Cela évite à tout le monde d'avoir à sonder la zone de réception du courrier.
Comme vous le soupçonniez, un événement peut fonctionner par sondage. Et si un événement est en quelque sorte lié à des événements externes, par exemple une pression sur une touche du clavier, une interrogation doit avoir lieu à un moment donné.
Il est également vrai que les événements ne nécessitent pas nécessairement un sondage. Par exemple, si l'événement survient lorsqu'un bouton est enfoncé, l'écouteur d'événements de ce bouton est une méthode que l'infrastructure graphique peut appeler lorsqu'elle détermine qu'un clic de la souris appuie sur le bouton. Dans ce cas, l'interrogation devait encore se produire pour que le clic de souris soit détecté, mais l'écouteur de souris est un élément plus passif connecté au mécanisme d'interrogation des primitives par le biais d'un chaînage d'événements.
Mise à jour: interrogation de matériel de bas niveau
Il s'avère que les périphériques USB et autres protocoles de communication modernes possèdent un ensemble de protocoles d'interaction assez fascinant, semblable à un réseau, permettant aux périphériques d'E / S, y compris les claviers et les souris, de se lancer dans des topologies ad hoc .
Il est intéressant de noter que les " interruptions " sont assez impératives, les choses synchrones, elles ne gèrent donc pas les topologies de réseau ad hoc . Pour résoudre ce problème, les " interruptions " ont été généralisées en paquets asynchrones de haute priorité appelés " transactions d'interruption " (dans le contexte de l'USB) ou " interruptions signalées par un message " (dans le contexte du PCI). Ce protocole est décrit dans une spécification USB:
L'essentiel semble être que les périphériques d'E / S et les composants de communication (comme les concentrateurs USB) agissent fondamentalement comme des périphériques réseau. Donc, ils envoient des messages, ce qui nécessite d'interroger leurs ports et autres. Cela réduit le besoin de lignes matérielles dédiées.
Les systèmes d’exploitation tels que Windows semblent gérer le processus d’interrogation lui-même, par exemple comme décrit dans la documentation MSDN du système
USB_ENDPOINT_DESCRIPTOR
, qui explique comment contrôler la fréquence à laquelle Windows interroge un contrôleur hôte USB pour les messages d’interruption / isochrones:Les protocoles de connexion au moniteur plus récents, tels que DisplayPort, semblent faire la même chose:
Cette abstraction autorise certaines fonctionnalités intéressantes, telles que l'exécution de 3 moniteurs à partir d'une seule connexion:
Sur le plan conceptuel, le point à retenir est que les mécanismes de scrutation permettent des communications série plus généralisées, ce qui est génial lorsque vous souhaitez des fonctionnalités plus générales. Ainsi, le matériel et le système d'exploitation interrogent beaucoup le système logique. Ensuite, les consommateurs abonnés à des événements peuvent apprécier que ces informations soient gérées par le système de niveau inférieur, sans avoir à écrire leurs propres protocoles d'interrogation / de transmission de message.
En fin de compte, des événements tels que les presses à clé semblent traverser une série d’événements assez intéressants avant d’aboutir au mécanisme de déclenchement d’événement impératif du niveau logiciel.
la source
Pull vs Push
Il existe deux stratégies principales pour vérifier si un événement s'est produit ou si un état spécifique est atteint. Par exemple, imaginez attendre une livraison importante:
L' approche par tirage (également appelée interrogation) est plus simple: vous pouvez l'implémenter sans aucune particularité. En revanche, il est souvent moins efficace, car vous risquez de faire des vérifications supplémentaires sans rien montrer.
D'autre part, l' approche push est généralement plus efficace: votre code ne s'exécute que lorsqu'il a quelque chose à faire. D'autre part, il faut un mécanisme pour enregistrer un auditeur / observateur / rappel 1 .
1 Malheureusement, un tel mécanisme manque généralement à mon facteur.
la source
À propos de l'unité en particulier - il n'y a pas d'autre moyen de vérifier l'entrée du joueur que de l'interroger à chaque image. Pour créer un écouteur d'événement, vous aurez toujours besoin d'un objet tel que "système d'événement" ou "gestionnaire d'événements" pour effectuer l'interrogation. Le problème ne sera donc renvoyé que dans une autre classe.
Certes, une fois que vous avez un gestionnaire d’événements, vous n’avez qu’une seule classe qui interroge l’entrée par image, mais cela ne présente aucun avantage évident en termes de performances. En effet, cette classe doit maintenant parcourir les écouteurs et les appeler, ce qui, en fonction de votre jeu. conception (comme dans le nombre d’auditeurs présents et la fréquence à laquelle le joueur utilise des entrées), pourrait en réalité coûter plus cher.
En dehors de tout cela, souvenez-vous de la règle d'or: l' optimisation prématurée est la racine de tout mal , ce qui est particulièrement vrai dans les jeux vidéo, où souvent le processus de rendu de chaque image coûte tellement cher, que de telles optimisations de script sont totalement insignifiantes.
la source
À moins que votre système d'exploitation / framework ne prenne en charge des événements tels que l'insertion de boutons, le débordement de la minuterie ou l'arrivée de messages, vous devrez implémenter ce modèle d'écouteur d'événements en utilisant de toute façon une interrogation (quelque part au-dessous).
Mais ne vous détournez pas de ce modèle simplement parce que vous ne bénéficiez pas immédiatement d'un avantage en termes de performances. Voici les raisons pour lesquelles vous devriez l’utiliser, que vous ayez ou non un support sous-jacent pour la gestion des événements.
Conclusion - vous avez eu la chance de participer à la discussion et appris une alternative au vote. Cherchez une occasion d'appliquer ce concept dans la pratique et vous comprendrez à quel point le code pourrait être élégant.
la source
La plupart des boucles d'événement sont construites au-dessus d'une primitive de multiplexage par interrogation fournie par le système d'exploitation. Sous Linux, cette primitive est souvent l' appel système
poll
(2) (mais pourrait être l'ancienselect
). Dans les applications à interface graphique, le serveur d'affichage ( Xorg ou Wayland, par exemple ) communique (via un socket (7) ou un tuyau (7) ) avec votre application. Lisez également à propos des protocoles système et de l'architecture X Window .Ces primitives d'interrogation sont efficaces. le noyau réveillera en pratique votre processus quand une entrée est faite (et une interruption est gérée).
Concrètement, votre bibliothèque de boîtes à outils de widgets communique avec votre serveur d’affichage, attend les messages et les envoie à vos widgets. Les bibliothèques de boîtes à outils telles que Qt ou GTK sont assez complexes (des millions de lignes de code source). Votre clavier et votre souris ne sont gérés que par le processus du serveur d'affichage (qui traduit ces entrées en messages d'événement envoyés aux applications clientes).
(Je simplifie; en fait les choses sont beaucoup plus complexes)
la source
Dans un système purement basé sur des interrogations, les sous-systèmes souhaitant savoir quand une action particulière se produit devront exécuter du code à tout moment. S'il existe de nombreux sous-systèmes devant réagir chacun dans un délai de 10 ms à la suite de certains événements non nécessairement uniques, ils doivent tous vérifier au moins 100 fois par seconde si leur événement s'est produit. Si ces sous-systèmes sont dans différents processus de threads (ou pire processus), cela nécessiterait de basculer dans chacun de ces threads ou processus à 100x / seconde.
Si de nombreuses fonctionnalités recherchées par les applications sont assez similaires, il serait peut-être plus efficace de disposer d'un sous-système de surveillance centralisé - peut-être piloté par une table - permettant de surveiller de nombreuses choses et d'observer si l'un d'entre elles a changé. S'il y a 32 commutateurs, par exemple, une plate-forme peut avoir pour fonction de lire tous les 32 commutateurs en un mot, ce qui permet au code du moniteur de vérifier si des commutateurs ont changé entre les scrutations et, dans le cas contraire, non. s'inquiéter de quel code pourrait être intéressé par eux.
Si de nombreux sous-systèmes souhaiteraient recevoir une notification lorsque quelque chose change, il peut être plus efficace de disposer d'un sous-système de surveillance dédié pour notifier les autres sous-systèmes lorsque des événements qui les intéressent se produisent, plutôt que de demander à chaque sous-système d'interroger ses propres événements. La mise en place d'un sous-système de surveillance dédié dans les cas où personne n'est intéressé par un événement représenterait toutefois un gaspillage de ressources. Si seuls quelques sous-systèmes sont intéressés par les événements, le coût de leur surveillance par les événements qui les intéressent peut être inférieur au coût de la mise en place d'un sous-système de surveillance dédié à usage général, mais le seuil de rentabilité Ce point varie considérablement entre les différentes plateformes.
la source
Un écouteur d’événement est comme une oreille qui attend un message. Lorsque l'événement se produit, le sous-programme choisi comme écouteur d'événement fonctionne à l'aide des arguments de l'événement.
Il y a toujours deux données importantes: le moment où l'événement se produit et l'objet où cet événement se produit. D'autres arguments sont plus de données sur ce qui s'est passé.
L'écouteur d'événement spécifie la réaction à celle qui se produit.
la source
Un écouteur d'événements suit le modèle Publish / Subscribe (en tant qu'abonné)
Dans sa forme la plus simple, un objet de publication conserve une liste des instructions des abonnés à exécuter lorsque quelque chose doit être publié.
Il aura une sorte de
subscribe(x)
méthode, où x dépend de la façon dont le gestionnaire d'événements est conçu pour gérer l'événement. Lorsque subscribe (x) est appelé, x est ajouté à la liste des instructions / références des abonnés des éditeurs.L'éditeur peut contenir toute, une partie ou aucune de la logique de gestion de l'événement. Il peut simplement exiger des références aux abonnés pour les notifier / les transformer avec sa logique spécifiée lorsque l'événement se produit. Il peut ne contenir aucune logique et nécessiter des objets d'abonné (méthodes / écouteurs d'événements) capables de gérer l'événement. Il est fort probable qu'il contienne un mélange des deux.
Lorsqu'un événement se produit, l'éditeur effectue une itération et exécute sa logique pour chaque élément de sa liste d'instructions / références d'abonnés.
Peu importe la complexité d'un gestionnaire d'événements, il suit ce modèle simple.
Exemples
Pour un exemple d'écouteur d'événements, vous fournissez un écouteur de méthode / fonction / instruction / événement à la méthode subscribe () du gestionnaire d'événements. Le gestionnaire d'événements ajoute la méthode à sa liste de rappels d'abonnés. Lorsqu'un événement se produit, le gestionnaire d'événements parcourt sa liste et exécute chaque rappel.
Par exemple, lorsque vous vous abonnez à la newsletter sur Stack Exchange, une référence à votre profil sera ajoutée à un tableau de la base de données des abonnés. Quand il sera temps de publier le bulletin d'information, la référence sera utilisée pour remplir un modèle du bulletin d'information qui sera envoyé à votre courrier électronique. Dans ce cas, x est simplement une référence à votre nom et l'éditeur dispose d'un ensemble d'instructions internes utilisées pour tous les abonnés.
la source