Gli eventi vengono utilizzati solo per la programmazione della GUI?


57

Gli eventi vengono utilizzati solo per la programmazione della GUI?

Come gestite la normale programmazione back-end quando succede qualcosa a quest'altra cosa?


6
A proposito, Event Source è un concetto completamente ortogonale alla programmazione degli eventi. Il concetto di base di Event Sourcing è che si memorizzano "eventi" o "modifiche" al proprio sistema, invece di memorizzare lo "stato" del proprio sistema. Ad esempio, puoi modellare il tuo conto bancario come a) Il tuo saldo (STATO) oppure b) Una serie di Transazioni (EVENTSOURCE).
Art

4
A seconda dell'utilizzo, un "evento" è in genere solo una forma di callback avvolto nello zucchero. I callback vengono utilizzati ovunque: se sei interessato, è probabilmente una buona parola chiave con cui iniziare una ricerca.
J ...

10
Sottolineerò anche che, anche se si passa a un livello basso come un microcontrollore, si troverà che l'hardware interrompe una funzione utile e debatably essenziale. Ottimo per i sistemi di controllo o IO di base come una caffettiera. Questi interrupt di processo non sono in realtà sostanzialmente diversi dagli eventi.
Dan,

No! Esempio pratico: eventi
Nodejs

2
Sei su Windows? Dai un'occhiata al Visualizzatore eventi. Divertiti.
Marc.2377,

Risposte:


106

No. Sono davvero utili per implementare gli osservatori e assicurarsi che le classi siano chiuse alle modifiche.

Diciamo che abbiamo un metodo che registra i nuovi utenti.

public void Register(user) {
    db.Save(user);
}

Quindi qualcuno decide che è necessario inviare un'e-mail. Potremmo farlo:

public void Register(user) {
    db.Save(user);
    emailClient.Send(new RegistrationEmail(user));
}

Ma abbiamo appena modificato una classe che dovrebbe essere chiusa alla modifica. Probabilmente va bene per questo semplice pseudo-codice, ma probabilmente la via della follia nel codice di produzione. Quanto tempo ci vorrà prima che questo metodo sia composto da 30 righe di codice che sono appena correlate allo scopo originale di creare un nuovo utente ??

È molto più bello lasciare che la classe esegua le sue funzionalità principali e organizzare un evento dicendo a chiunque stia ascoltando che un utente è stato registrato e possono intraprendere qualsiasi azione necessaria (come inviare un'e-mail).

public void Register(user) {
    db.Save(user);

    RaiseUserRegisteredEvent(user);
}

Ciò mantiene il nostro codice pulito e flessibile. Uno dei pezzi spesso trascurati di OOP è che le classi si scambiano messaggi . Gli eventi sono questi messaggi.


37
Ho letto questo e penso al nostro codice "crea prenotazione" e piango per un po 'e cerco un posto migliore:' (
sara

1
+1, ottima risposta. Solo una domanda tangenziale (questo mi ha infastidito un po '): c'è un motivo speciale per cui hai iniziato i nomi dei tuoi metodi (Registra, Salva e Invia) con lettere maiuscole? Ovviamente, ciò non influisce sull'utilità di questa risposta.
Pedro A

14
@Hamsteriffic Sono principalmente uno sviluppatore C # e questa è la convenzione generalmente accettata. Nessun altro motivo.
RubberDuck,

6
@Hamsterifficas un'aggiunta, quello che chiami lowerCase ma contiene una maiuscola nel mezzo è spesso chiamato camelCase, perché ha delle gobbe nel mezzo. Ciò lo distingue da snake_case, dove le parole minuscole sono separate da caratteri di sottolineatura, che è familiare a Python e alla maggior parte dei linguaggi di shell, per citarne alcuni.
Aaron,

5
Gli eventi sono un tipo di questi messaggi, direi. Anche le chiamate di metodo devono essere considerate passaggio di messaggi.
jpmc26,

53

No.

Un classico esempio di eventi utilizzati nella logica non GUI sono i trigger di database.

I trigger sono codici che vengono eseguiti quando si verifica un determinato evento (INSERT, DELETE, ecc.). Mi sembra un evento.

Questa è la definizione di evento di Wikipedia:

Nell'informatica, un evento è un'azione o occorrenza riconosciuta dal software che può essere gestita dal software. Gli eventi del computer possono essere generati o attivati ​​dal sistema, dall'utente o in altri modi. In genere, gli eventi vengono gestiti in modo sincrono con il flusso del programma, ovvero il software può avere uno o più posti dedicati in cui gli eventi vengono gestiti, spesso un ciclo di eventi. Una fonte di eventi include l'utente, che può interagire con il software tramite, ad esempio, la pressione dei tasti sulla tastiera. Un'altra fonte è un dispositivo hardware come un timer. Il software può anche attivare il proprio set di eventi nel loop degli eventi, ad esempio per comunicare il completamento di un'attività. Si dice che il software che modifica il suo comportamento in risposta agli eventi sia guidato dagli eventi, spesso con l'obiettivo di essere interattivo.

Non tutti gli eventi sono generati dall'utente. Alcuni sono generati da un timer come una crontab di un database INSERT come ho detto prima.

La definizione afferma inoltre che alcuni programmi o sistemi sono "guidati dagli eventi, spesso con l'obiettivo di essere interattivi" , da cui si può derivare che lo scopo o l'utilità degli eventi non sono solo, ma piuttosto spesso, fornire interattività (come le GUI sebbene non necessariamente GUI, poiché i programmi CLI possono anche essere interattivi).


2
Ci penso sempre quando sento parlare dei trigger di database: thecodelesscode.com/case/42
Almo,

Come ex sviluppatore DBA, ora mi arrabbio ogni volta che sento gente parlare dell'utilizzo dei trigger senza considerare le prestazioni del DB più ampio.
Three Value Logic,

27

La programmazione basata su eventi viene effettivamente utilizzata anche per la programmazione di server altamente performanti.

In un tipico carico di lavoro del server, la maggior parte del tempo che elabora un risultato proviene effettivamente dall'I / O. Ad esempio, l'estrazione di dati da un'unità disco rigido (7200 RPM) può richiedere fino a 8,3 ms. Per un moderno processore GHz, ciò equivarrebbe a ~ 1 milione di cicli di clock. Se una CPU dovesse aspettare i dati ogni volta (senza fare nulla), perderemmo MOLTI cicli di clock.

Le tecniche di programmazione tradizionali aggirano questo problema introducendo più thread . La CPU tenta di eseguire centinaia di thread contemporaneamente. Tuttavia, il problema di questo modello è che, ogni volta che una CPU cambia thread, richiede il cambio di contesto per centinaia di cicli di clock . Un interruttore di contesto è quando la CPU copia la memoria thread-local nei registri della CPU e memorizza anche il registro / stato del thread precedente nella RAM.

Inoltre, ogni thread deve consumare una certa quantità di memoria per memorizzare il suo stato.

Oggi c'è stata una spinta per i server che ha un singolo thread, che gira in un ciclo. Quindi i pezzi di lavoro vengono inseriti in un pump dei messaggi , che funge da coda per il singolo thread (proprio come in un thread dell'interfaccia utente). Invece di attendere il completamento del lavoro, la CPU imposta un evento di richiamata, per cose come l'accesso al disco rigido. Ciò riduce il cambio di contesto.

Il miglior esempio di tale server è Node.js , che ha dimostrato di essere in grado di gestire 1 milione di connessioni simultanee con hardware modesto, mentre un server Java / Tomcat avrebbe difficoltà a qualche migliaio.


2
"Hardware modesto" è un po 'fuorviante. Avrai bisogno di 8 GB + per Node, oltre a tutto ciò che utilizza il sistema operativo. E se hai così tanta memoria, Tomcat può facilmente gestire alcune migliaia di connessioni. Certo, c'è una grande differenza, ma non è 1000x.
Paul Draper,

@PaulDraper no non può. E no non lo fa. Sono necessari 8 GB + solo per lo stack per 8000 thread. Questa è la grande differenza.
Art

3
@PaulDraper oltre a 8 GB è molto modesto per gli standard dei server. Ho lavorato su macchine con 128 GB di RAM e quelle non sono nemmeno completamente caricate. I ram stick costano di più dell'intera macchina.
Art

dipende dalle dimensioni dello stack. Oracle / OpenJDK viene impostato automaticamente su 1 MB sulla maggior parte delle piattaforme per 64 bit e 512 KB per 32 bit. Se prendi solo le impostazioni predefinite, avresti ragione. Ma i valori predefiniti non sono come si arriva alle connessioni 1M Node;) Comunque, 128K è abbondante; puoi cavartela con ancora meno. Sarebbe 1 GB di spazio di stack per 8000 thread.
Paul Draper,

6
Ti sbagli. Anche con dimensioni dello stack predefinite, sono necessari solo 8 GiB di memoria virtuale . La memoria è impegnata al volo secondo necessità. In genere, è necessaria una sola pagina per stack, a meno che non si stia effettivamente utilizzando la memoria aggiuntiva. E in pratica, la maggior parte dei thread in un tale sistema ha solo quelle pile (di solito) a 64 kiB. L'utilizzo della memoria virtuale è un grosso problema per i sistemi operativi a 32 bit, ma non tanto per i 64 bit. Ti imbatti in altri limiti molto prima - come l'esaurimento della porta TCP, ad esempio :) E dove pensi che siano archiviate le "pseudo-pile" di nodo? Esatto, sul mucchio.
Luaan,

10

Gli eventi sono anche ampiamente utilizzati nella programmazione di rete (ad es. Nginx) per evitare costosi loop di attesa e fornire invece un'interfaccia pulita per sapere esattamente quando è disponibile una determinata operazione (I / O, dati urgenti ecc.). Questa è anche una soluzione al problema C10k .

L'idea di base è fornire al sistema operativo un set di socket (ad es. Connessioni di rete) per monitorare gli eventi, tutti o solo alcuni a cui sei particolarmente interessato (dati disponibili per la lettura, ad esempio); quando tale attività viene rilevata dal sistema operativo su uno dei socket nell'elenco, riceverai una notifica dell'evento che stavi cercando dall'API, che dovrai quindi risolvere da dove proviene e agire di conseguenza .

Ora, questa è una visione di basso livello e astratta, inoltre difficile da scalare bene. Tuttavia, ci sono molti framework di livello superiore che affrontano questo problema in modo uniforme e multipiattaforma: Twisted for Python, Boost.Asio per C ++ o libevent per C mi vengono in mente.


+1 "costosi loop di attesa": in altre parole, è utile in tutti i processi paralleli che comportano inattività (attesa), nonché la sincronizzazione tra tali processi (messaggi o eventi). Come gran parte del mondo reale funziona.
13

È interessante scoprire che i socket sono stati originariamente progettati come una forma di IPC su una singola macchina, prima che esistesse la rete.

5

I sistemi integrati sono quasi sempre intrinsecamente guidati da eventi, anche se non sono programmati esplicitamente come tali.

Questi eventi provengono da cose come interruzioni hardware, pressioni di pulsanti, letture periodiche da analogico a digitale, scadenze del timer, ecc.

I sistemi embedded a bassa potenza hanno ancora più probabilità di essere guidati da eventi; trascorrono la maggior parte del loro tempo a dormire (CPU in modalità a basso consumo), in attesa che accada qualcosa (quel "qualcosa" è un evento).

Uno dei framework più comuni e popolari per i sistemi embedded basati su eventi è la Quantum Platform (QP) (il QP funziona anche con Linux, Windows e qualsiasi sistema operativo simile a unix.) Le macchine a stati sono una scelta naturale per la programmazione basata su eventi, poiché il programma non è "sequenziale" nel senso tipico, piuttosto, è un insieme di "callback" che vengono invocati a seconda dello stato del sistema e dell'evento corrente.


3

Messaggi di evento Gregor Hohpe.

Architetture guidate da eventi Gregor Hohpe.

Architettura SEDA , gallese, Culler, Brewer.

come gestisci nella normale programmazione back-end quando succede qualcosa, fai quest'altra cosa?

La macchina a stati finiti è un approccio comune

Given(State.A)
When(Event.B)
Then(State.C)
    .and(Consequences.D)

2
1, questa non è una risposta coerente e 2, FSM non sono buoni esempi di utilizzo degli eventi.
whatsisname

1
FSM. Sono sicuro che la religione pastafariana osserva una serie di eventi ;-)
dal

0

Nei sistemi integrati, si verificano eventi durante gli interrupt. Esistono molte fonti di interrupt, dai timer all'I / O.

Inoltre, RTOS può contenere anche eventi. Un esempio è in attesa di un messaggio da un'altra attività.


0

Per il sistema non incorporato, ma qualcosa che stavo facendo in C # era il sistema SCADA. Ci sono stati molti eventi legati a ciò che stava accadendo nel magazzino quando il carico veniva scaricato parte dell'evento generato dal sistema e l'altra parte stava scrivendo il nuovo stato nel database. Naturalmente avevamo un client GUI ma era solo per mostrare lo stato del database che rifletteva lo stato del magazzino. Quindi era un software server back-end basato su eventi e threading. Abbastanza stimolante da sviluppare.

https://en.wikipedia.org/wiki/SCADA

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.