ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/cvsroot/docs/ev.pod
Revision: 1.2
Committed: Mon Jan 7 23:12:53 2008 UTC (18 years, 9 months ago) by root
Branch: MAIN
Changes since 1.1: +51 -51 lines
Log Message:
*** empty log message ***

File Contents

# Content
1 =head1 NAME
2
3 EV - (noch) ein Event-Modell für Perl
4
5 =head1 Was?
6
7 EV ist ein Perl-Modul, das Ereignisgesteuertes Programmieren
8 unterstützt. Darin unterscheidet es sich erst einmal nicht von anderen
9 dedizierten Modulen wie "Event" oder die in jedes Toolkit (Gtk, Tk etc.)
10 eingebaute Ereignisverarbeitung.
11
12 EV ist des weiteren eine Schnittstelle zur "Libev"-Bibliothek, eine Art
13 Libevent-Klon, und erbt deshalb deren Features (worin sich EV nun von
14 einigen anderen Modulen unterscheidet):
15
16 =over 4
17
18 =item * Korrektheit
19
20 Die meisten Ereignis-Bibliotheken funktionieren gut, solange nichts
21 unvorhergesehenes passiert.
22
23 Die meisten versagen kläglich, wenn die Systemuhr verstellt wird
24 (Zeitsprünge): Aus einem 10s-Timeout können bei Tk (Event, Glib etc.)
25 problemlos mal Jahre werden, aus einem Tag wenige Sekunden. EV unterstützt
26 sowohl relative Timer ("wecke mich in 10 Minuten auf, egal ob ntpd die
27 Uhr ändert oder nicht) als auch absolute Timer ("wecke mich 2008-10-10
28 12:17:23.445 auf, egal wie lange das wirklich dauert" oder gar "wecke
29 mich zur nächsten Mitternacht auf"), was kein anderes mir bekanntes
30 Event-Modell unterstützt.
31
32 Registriert man bei Tk (Event::Lib, ...) zwei Watcher auf denselben
33 Filehandle, so kann einer davon verloren gehen (nicht notwendigerweise
34 immer der ältere oder neuere).
35
36 Stellt man bei Event die "richtigen" Prioritäten ein, kriegt man eine
37 stetig wachsende Event-Queue die nicht kleiner wird (was allerdings selten
38 in Out-Of-Memory-Situationen endet, denn Event wird vorher zu langsam).
39
40 Das alles sind Kleinigkeiten - bis das Programm deshalb mal "hängt", 100%
41 Rechenzeit verbraucht oder gar sporadisch versagt.
42
43 Außerdem haben viele Event-Modelle (Event, Glib, Tk...) ein von Perl
44 abweichendes Objektmodell: verliert man beim Event oder Glib die Referenz
45 auf den Watcher, so hat man bestenfalls ein Memory-Leak. Die EV-Watcher
46 bestehen genau so lange, wie Referenzen darauf zeigen wie jedes andere
47 Perl-Objekt auch.
48
49 Fork ist ein ganz spezielles Problem: wenige Event-Bibliotheken
50 unterstützen es direkt, vor allem diejenigen, die Epoll, Kqueue
51 o.ä. benutzen, da diese Schnittstellen sehr fork-feindlich sind. EV
52 unterstützt fork indem es den Kernel-Zustand im Kindprozess automatisch
53 wiederherstellt, sofern es benutzt wird.
54
55 =item * Geschwindigkeit
56
57 EV benutzt "die richtigen" Algorithmen zur Verwaltung: Heaps für die
58 Verwaltung der Timer (keine lineare Liste oder ähnliches wie alle
59 anderen), Arrays, wenn es um viele Watcher geht, Listen, wenn es nur
60 wenige (meist einen) geht. Auch geht Libev nicht vor jedem Pollen alle
61 seine Watcher (Event, Glib, ...) durch um zu sehen ob sie noch alle da
62 sind.
63
64 Dadurch skaliert EV nicht nur hervorragend in die Bereiche von
65 hunderttausenden Filehandles und Timern (falls man das braucht), sondern
66 ist auch mit wenigen davon sehr schnell (was mindstens genauso wichtig
67 ist).
68
69 Auch die Perl-Schnittstelle selbst wurde geschrieben, um unnötige
70 Laufzeitkosten zu vermeiden: EV erzeugt einen Watcher immerhin 40 mal
71 schneller als Event und fast viermal so schnell wie Glib, womit EV +
72 AnyEvent immer noch schneller sind als "nacktes" Glib.
73
74 Auch der Speicherverbrauch ist sehr gering: EV-Watcher sind schlichte
75 geblesste Strings die den Libev-Watcher enthalten. Diese wiederum sind im
76 Vergleich mit anderen Bibliotheken recht klein (weniger als 100 Bytes).
77
78 =item * Skalierbarkeit
79
80 Nicht nur die Algorithmen, auch die Schnittstelle zum Betriebssystem muss
81 skalierbar sein, und das bedeutet leider auch: nicht portabel. Jedes
82 Betriebssystem braucht sein eigenes Rezept und daher auch sein eigenes
83 Backend: Libev unterstützt Epoll, Kqueue und Solaris' Event Ports.
84
85 Einige Backends sind sehr begrenzt (Kqueue z.B. ist auf fast allen System
86 kaputt und supported bestenfalls Sockets) aber in ein anderen Backend
87 integrierbar, so kann man z.B. ein Kqueue-Backend (supported nur Sockets
88 zuverlässig auf FreeBSD) in ein "herkömmliches" Poll-basiertes Backend
89 integrieren.
90
91 =item * Watcher-Typen
92
93 Neben den üblichen I/O Watchern und Timern (derer es zwei grundsätzlich
94 verschiedene Typen in EV gibt), bietet EV noch speziellere
95 Watchertypen für POSIX-Signale, Prozess-Watcher, Idle-Watcher (für
96 "Hintergrundprozesse"), Prepare/Check-Watcher, mit denen man EV-fremde
97 Event-Modelle oder -Benutzer integrieren kann und Stat-Watcher, mit denen
98 man Dateisystemobjekte auf Veränderungen überwachen kann. Ganz spezielle
99 Watcher, um C<fork()> zu erkennen oder andere Backends zu integrieren gibt
100 es natürlich auch.
101
102 =item * C-Schnittstelle
103
104 Das EV-Modul exportiert die komplette Libev-API auch auf XS-Ebene, was
105 so nur noch Event bietet (bei anderen Modulen muss man auf positive
106 Eigenschaften von Shared-Libraries vertrauen).
107
108 =back
109
110
111 =head1 Warum?
112
113 EV ist, wie die zugrunde liegende Libev, sehr jung (Ende 2007 erschien
114 die erste Version), und die Entstehung war mehr Zufall als Absicht: Seit
115 ca. 1998 benutze ich regelmäßig und viel das Event-Modul, welches
116 problemlos als das ausgereifteste der verfügbaren Event-Module gelten
117 durfte.
118
119 Im Laufe der Jahre stieß ich auf eine Menge kleinerer Probleme mit anderen
120 Event-Modellen (siehe weiter oben), doch die Anstrengung, eine eigene
121 Bibliothek zu schreiben, wollte ich nicht aufbringen.
122
123 Speicherverbrauch war eigentlich nie ein Problem, die Beschränkung auf
124 C<select> und C<poll> schon eher, aber man hat ja schnelle Rechner die
125 das kompensieren (und wenn man nicht drauf achtet, was die Rechenzeit
126 verbraucht, stört es ja sowieso nie).
127
128 An die echten Fehler in z.B. Event gewöhnt man sich mit der Zeit, bzw.
129 findet mehr oder weniger akzeptable Umleitungen um das Problem, oder
130 vermeidet den Einsatz in solchen Fällen ganz.
131
132 Eines Tages kam jedoch die Notwendigkeit, wirklich viele Filehandles
133 effizient zu verwalten, und da Libevent sowas wie der Standard für
134 Performance zu sein schien und es dafür keine Perl-Schnittstelle gab
135 (das ist falsch, es gab eine, nämlich C<Event::Lib>, aber ich habe sie
136 trotz suchens auf CPAN nicht wahrgenommen), fing' ich an, eine eigene
137 Schnittstelle zu Libevent zu schreiben.
138
139 Wenig erfreut war ich, als ich herausfand, daß Libevent die gleichen
140 Probleme wie Tk hat (nicht mehrere Watcher auf einem Filehandle) und auch
141 nicht wenige Schwächen in der API. Das Erlebnis war derart frustrierend,
142 daß ich mich entschieden habe, endgültig mein eigenes Ding' zu machen. Wie
143 erwartet, war es mehr Arbeit, als ich eigentlich investieren wollte,
144 aber nach einigen Monaten hatte ich etwas gebrauchsfähiges, daß sogar
145 bei Benchmarks gegenüber dem "Standard" (nämlich Libevent) hervorragend
146 abschneidet.
147
148 Da die meisten meiner Module AnyEvent benutzen, und die API von EV (im
149 Geiste...) der von Event ähnelt, war die Umstellung aller meiner wichtigen
150 Projekte (gvpe, rxvt-unicode, Deliantra, mein Webserver sowie mehrere
151 kommerzielle Anwendungen) kein Problem, was natürlich ein sehr guter Test
152 für das Modul war (und ist).
153
154 EV ist somit das Ergebnis von knapp 10 Jahren Erfahrung mit
155 anderen Event-Modellen, deren Stärken und Schwächen und deren
156 Perl-Schnittstelle: alle mir bekannten Probleme wurden adresssiert.
157
158
159 =head1 Wie?
160
161 Nach so viel Blabla wirds Zeit für Code-Beispiele.
162
163 Einen langweiligen Timer realisiert man so.
164
165 use EV;
166
167 my $timer = EV::timer 1, 2, sub {
168 warn "man rief' mich auf nach 1s dann alle 2s. yeah.";
169 };
170
171 EV::loop;
172
173 Das gibt nach einer Sekunde ein warn, und danach alle zwei Sekunden, bis
174 in alle Ewigkeit/Reset/SIGINT etc.
175
176 EV::loop kehrt automatisch zurück, wenn es keine aktiven Watcher mehr gibt
177 (das nennt man "Deadlock"):
178
179 my $delay = EV::timer 1, 0, sub {
180 warn "nur einmal nach 1s werde ich aufgerufen.\n";
181 };
182
183 EV::loop;
184
185 Das läuft nur für eine Sekunde. Wichtig ist, daß man das Watcher-Objekt,
186 das der Konstruktor liefert, auch aufbewahrt, denn wenn man es vergisst,
187 wird der Watcher automatisch deaktiviert. Hier kehrt C<EV::loop> sofort
188 zurück, wenn keine sonstigen Watcher aktiv sind, denn der Timer wird
189 erzeugt, gestartet und sofort wieder gelöscht:
190
191 EV::timer 10, 10, sub { };
192 EV::loop;
193
194 I/O-Watcher gehen genauso einfach. Das folgende Beispiel "loop"ed so
195 lange, bis man auf STDIN eine Zeile die mit C<q> beginnt, eingibt (z.b.
196 "quit"):
197
198 my $stdin_watcher = EV::io *STDIN, EV::READ, sub {
199 my $line = <STDIN>;
200
201 # $_[0] enthält das watcher-objekt
202 $_[0]->stop if $line =~ /^q/;
203 };
204
205 EV::loop;
206
207 Alternativ kann man den Watcher auch "einfach" C<undef>'en (Perl macht das
208 ein bisschen eklig):
209
210 my $stdin_watcher;
211 $stdin_watcher = EV::io *STDIN, EV::READ, sub {
212 my $line = <STDIN>;
213
214 undef $stdin_watcher if $line =~ /^q/;
215 };
216
217 EV::loop;
218
219 =head2 Spezialitäten
220
221
222 =head1 Und wie noch?
223
224 =head1 Hä?
225
226 =back
227