Werden Ereignisse nur für die GUI-Programmierung verwendet?
Wie gehen Sie bei der normalen Backend-Programmierung vor, wenn mit dieser anderen Sache etwas passiert?
Werden Ereignisse nur für die GUI-Programmierung verwendet?
Wie gehen Sie bei der normalen Backend-Programmierung vor, wenn mit dieser anderen Sache etwas passiert?
Antworten:
Nee. Sie sind sehr praktisch, um Observer zu implementieren und sicherzustellen, dass Klassen für Änderungen gesperrt sind.
Angenommen, wir haben eine Methode, mit der neue Benutzer registriert werden.
public void Register(user) {
db.Save(user);
}
Dann entscheidet jemand, dass eine E-Mail gesendet werden soll. Wir könnten dies tun:
public void Register(user) {
db.Save(user);
emailClient.Send(new RegistrationEmail(user));
}
Aber wir haben gerade eine Klasse geändert, die für Änderungen geschlossen sein soll. Wahrscheinlich in Ordnung für diesen einfachen Pseudocode, aber wahrscheinlich den Weg zum Wahnsinn im Produktionscode. Wie lange dauert es, bis diese Methode 30 Codezeilen enthält, die kaum mit dem ursprünglichen Zweck der Erstellung eines neuen Benutzers zusammenhängen?
Es ist viel angenehmer, die Klasse ihre Kernfunktionen ausführen zu lassen und ein Ereignis auszulösen, das jedem mitteilt, dass ein Benutzer registriert wurde, und er kann die erforderlichen Maßnahmen ergreifen (z. B. eine E-Mail senden).
public void Register(user) {
db.Save(user);
RaiseUserRegisteredEvent(user);
}
Dies hält unseren Code sauber und flexibel. Einer der häufig übersehenen Aspekte von OOP ist, dass Klassen sich gegenseitig Nachrichten senden . Ereignisse sind diese Nachrichten.
Nee.
Ein klassisches Beispiel für Ereignisse, die in einer Nicht-GUI-Logik verwendet werden, sind Datenbank-Trigger.
Trigger sind Code, der ausgeführt wird, wenn ein bestimmtes Ereignis eintritt (INSERT, DELETE usw.). Scheint für mich ein Ereignis zu sein.
Dies ist die Wikipedia-Definition des Ereignisses:
Beim Rechnen ist ein Ereignis eine von der Software erkannte Aktion oder ein Ereignis, das von der Software verarbeitet werden kann. Computerereignisse können vom System, vom Benutzer oder auf andere Weise generiert oder ausgelöst werden. In der Regel werden Ereignisse synchron mit dem Programmablauf verarbeitet. Das heißt, die Software verfügt möglicherweise über einen oder mehrere dedizierte Bereiche, an denen Ereignisse verarbeitet werden, häufig eine Ereignisschleife. Eine Ereignisquelle umfasst den Benutzer, der mit der Software beispielsweise über Tastenanschläge auf der Tastatur interagieren kann. Eine andere Quelle ist ein Hardwaregerät wie ein Timer. Die Software kann auch einen eigenen Ereignissatz in der Ereignisschleife auslösen, um z. B. den Abschluss einer Aufgabe mitzuteilen. Software, die ihr Verhalten als Reaktion auf Ereignisse ändert, wird als ereignisgesteuert bezeichnet, häufig mit dem Ziel, interaktiv zu sein.
Nicht alle Ereignisse werden vom Benutzer generiert. Einige werden von einem Timer wie einem crontab von einer Datenbank INSERT wie ich bereits erwähnt habe generiert.
Die Definition besagt auch, dass einige Programme oder Systeme "ereignisgesteuert sind, häufig mit dem Ziel, interaktiv zu sein" , woraus abgeleitet werden kann, dass der Zweck oder der Nutzen von Ereignissen nicht nur darin besteht, sondern häufig Interaktivität bereitzustellen (wie z. B. GUIs) obwohl nicht notwendigerweise GUIs, da CLI-Programme auch interaktiv sein können).
Die ereignisbasierte Programmierung wird tatsächlich auch für die hochleistungsfähige Serverprogrammierung verwendet.
Bei einer typischen Serverauslastung stammt ein Großteil der Zeit für die Verarbeitung eines Ergebnisses aus E / A. Das Abrufen von Daten von einem Festplattenlaufwerk mit 7200 U / min kann beispielsweise bis zu 8,3 ms dauern. Bei einem modernen GHz-Prozessor entspräche dies ~ 1 Million Taktzyklen. Wenn eine CPU jedes Mal auf die Daten warten würde (nichts tun würde), würden wir VIELE Taktzyklen verlieren.
Herkömmliche Programmiertechniken umgehen dies, indem sie mehrere Threads einführen . Die CPU versucht, Hunderte von Threads gleichzeitig auszuführen. Das Problem ist jedoch, die in diesem Modell das heißt, jedes Mal , wenn ein CPU - Thread umschaltet, erfordert es Hunderte von Taktzyklen , um Kontextschalter . Ein Kontextwechsel erfolgt, wenn die CPU den Thread-lokalen Speicher in die Register der CPU kopiert und auch das Register / den Zustand des alten Threads im RAM speichert.
Zusätzlich muss jeder Thread eine bestimmte Menge an Speicher zum Speichern seines Status belegen.
Heute gab es einen Push für Server mit einem einzigen Thread, der in einer Schleife ausgeführt wird. Anschließend werden Arbeitsstücke auf eine Nachrichtenpumpe verschoben , die als Warteschlange für den einzelnen Thread fungiert (ähnlich wie bei einem UI-Thread). Anstatt auf die Beendigung der Arbeit zu warten, setzt die CPU ein Rückrufereignis für Dinge wie den Festplattenzugriff. Das reduziert die Kontextumschaltung.
Das beste Beispiel für einen solchen Server ist Node.js , von dem gezeigt wurde, dass es 1 Million gleichzeitige Verbindungen mit bescheidener Hardware verarbeiten kann, während ein Java / Tomcat- Server mit einigen Tausend kämpfen würde.
Ereignisse werden auch häufig in der Netzwerkprogrammierung verwendet (z. B. Nginx), um teure Warteschleifen zu vermeiden und stattdessen eine saubere Schnittstelle bereitzustellen, um genau zu wissen , wann eine bestimmte Operation verfügbar ist (E / A, dringende Daten usw.). Dies ist auch eine Lösung für das C10k-Problem .
Die Grundidee besteht darin, dem Betriebssystem eine Reihe von Sockets (dh Netzwerkverbindungen) zur Überwachung von Ereignissen bereitzustellen, die alle oder nur einige, an denen Sie besonders interessiert sind (z. B. zum Lesen verfügbare Daten). Wenn das Betriebssystem eine solche Aktivität auf einem der Sockets in der Liste erkennt, erhalten Sie eine Benachrichtigung über das Ereignis, das Sie von der API gesucht haben. Anschließend müssen Sie herausfinden, woher es kommt, und entsprechend vorgehen .
Nun, dies ist eine einfache und abstrakte Ansicht, die außerdem schwierig zu skalieren ist. Es gibt jedoch viele übergeordnete Frameworks, die sich plattformübergreifend damit befassen: Twisted für Python, Boost.Asio für C ++ oder libevent für C.
Eingebettete Systeme sind fast immer inhärent ereignisgesteuert, auch wenn sie nicht explizit als solche programmiert sind.
Diese Ereignisse kommen von Dingen wie Hardware-Interrupts, Tastendrücken, periodischen Analog-Digital-Ablesungen, Timer-Ablaufen usw.
Embedded-Systeme mit geringem Stromverbrauch sind sogar eher ereignisgesteuert. Sie verbringen die meiste Zeit im Schlaf (CPU im Energiesparmodus) und warten darauf, dass etwas passiert (dieses "Etwas" ist ein Ereignis).
Eines der gebräuchlichsten und beliebtesten Frameworks für ereignisgesteuerte eingebettete Systeme ist die Quantum-Plattform (QP) (das QP funktioniert auch unter Linux, Windows und allen Unix-ähnlichen Betriebssystemen). da das Programm im typischen Sinne nicht "sequentiell" ist, handelt es sich vielmehr um eine Reihe von "Rückrufen", die abhängig vom Systemstatus und dem aktuellen Ereignis aufgerufen werden.
Ereignismeldungen Gregor Hohpe.
Ereignisgesteuerte Architekturen Gregor Hohpe.
SEDA-Architektur , Waliser, Culler, Brauer.
Wie gehen Sie bei der normalen Backend-Programmierung vor, wenn etwas passiert, machen Sie das andere?
Finite State Machine ist ein gängiger Ansatz
Given(State.A)
When(Event.B)
Then(State.C)
.and(Consequences.D)
In eingebetteten Systemen treten Ereignisse während Interrupts auf. Es gibt viele Interruptquellen, von Timern bis zu E / A.
RTOS kann auch Ereignisse haben. Ein Beispiel wartet auf eine Nachricht von einer anderen Aufgabe.
Für nicht eingebettete Systeme, aber etwas, was ich in C # tat, war SCADA-System. Es gab viele Ereignisse im Zusammenhang mit dem, was im Warehouse geschah, als das Laden eines Teils des vom System generierten Ereignisses beendet wurde und ein anderer Teil einen neuen Status in die Datenbank schrieb. Wir hatten natürlich einen GUI-Client, aber er sollte nur den Status der Datenbank anzeigen, der den Status des Lagers widerspiegelt. Es handelte sich also um Backend-Server-Software, die auf Ereignissen und Threading basierte. Sehr herausfordernd zu entwickeln.