ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/cvsroot/docs/ev.pod
Revision: 1.10
Committed: Sun Jan 13 03:12:05 2008 UTC (18 years, 8 months ago) by root
Branch: MAIN
Changes since 1.9: +1 -1 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 andere Backends
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 Kompatibilität
103
104 EV wird von AnyEvent voll unterstützt, so daß Module oder Programme, die
105 AnyEvent benutzen, ohne Quellcodeänderungen sofort mit EV benutzt werden
106 können.
107
108 =item C-Schnittstelle
109
110 Das EV-Modul exportiert die komplette Libev-API auch auf XS-Ebene, was
111 so nur noch Event bietet (bei anderen Modulen muss man auf positive
112 Eigenschaften von Shared-Libraries vertrauen).
113
114 =back
115
116
117 =head1 Warum?
118
119 EV ist, wie die zugrunde liegende Libev, sehr jung (Ende 2007 erschien
120 die erste Version), und die Entstehung war mehr Zufall als Absicht: Seit
121 ca. 1998 benutze ich regelmäßig und viel das Event-Modul, welches
122 problemlos als das ausgereifteste der verfügbaren Event-Module gelten
123 durfte.
124
125 Im Laufe der Jahre stieß ich auf eine Menge kleinerer Probleme mit anderen
126 Event-Modellen (siehe weiter oben), doch die Anstrengung, eine eigene
127 Bibliothek zu schreiben, wollte ich nicht aufbringen.
128
129 Speicherverbrauch war eigentlich nie ein Problem, die Beschränkung auf
130 C<select> und C<poll> schon eher, aber man hat ja schnelle Rechner die
131 das kompensieren (und wenn man nicht drauf achtet, was die Rechenzeit
132 verbraucht, stört es ja sowieso nie).
133
134 An die echten Fehler in z.B. Event gewöhnt man sich mit der Zeit, bzw.
135 findet mehr oder weniger akzeptable Umleitungen um das Problem, oder
136 vermeidet den Einsatz in solchen Fällen ganz.
137
138 Eines Tages kam jedoch die Notwendigkeit, wirklich viele Filehandles
139 effizient zu verwalten, und da Libevent sowas wie der Standard für
140 Performance zu sein schien und es dafür keine Perl-Schnittstelle gab
141 (das ist falsch, es gab eine, nämlich C<Event::Lib>, aber ich habe sie
142 trotz suchens auf CPAN nicht wahrgenommen), fing' ich an, eine eigene
143 Schnittstelle zu Libevent zu schreiben.
144
145 Wenig erfreut war ich, als ich herausfand, daß Libevent die gleichen
146 Probleme wie Tk hat (nicht mehrere Watcher auf einem Filehandle) und auch
147 nicht wenige Schwächen in der API. Das Erlebnis war derart frustrierend,
148 daß ich mich entschieden habe, endgültig 'mein eigenes Ding' zu machen. Wie
149 erwartet, war es mehr Arbeit, als ich eigentlich investieren wollte,
150 aber nach einigen Monaten hatte ich etwas gebrauchsfähiges, daß sogar
151 bei Benchmarks gegenüber dem "Standard" (nämlich Libevent) hervorragend
152 abschneidet.
153
154 Da die meisten meiner Module AnyEvent benutzen, und die API von EV (im
155 Geiste...) der von Event ähnelt, war die Umstellung aller meiner wichtigen
156 Projekte (gvpe, rxvt-unicode, Deliantra, mein Webserver sowie mehrere
157 kommerzielle Anwendungen) kein Problem, was natürlich ein sehr guter Test
158 für das Modul war (und ist).
159
160 EV ist somit das Ergebnis von knapp 10 Jahren Erfahrung mit
161 anderen Event-Modellen, deren Stärken und Schwächen und deren
162 Perl-Schnittstelle: alle mir bekannten Probleme wurden adresssiert.
163
164
165 =head1 Wie?
166
167 Nach so viel Blabla wird's Zeit für Code-Beispiele.
168
169 Einen langweiligen Timer realisiert man so.
170
171 use EV;
172
173 my $timer = EV::timer 1, 2, sub {
174 warn "zeitstempel: " . EV::now;
175 warn "man rief' mich auf nach 1s dann alle 2s. yeah.";
176 };
177
178 EV::loop;
179
180 Das gibt nach einer Sekunde ein warn, und danach alle zwei Sekunden, bis
181 in alle Ewigkeit/Reset/SIGINT etc.
182
183 EV::loop kehrt automatisch zurück, wenn es keine aktiven Watcher mehr gibt
184 (das nennt man "Deadlock"):
185
186 my $delay = EV::timer 1, 0, sub {
187 warn "nur einmal nach 1s werde ich aufgerufen.\n";
188 };
189
190 EV::loop;
191
192 Das läuft nur für eine Sekunde. Wichtig ist, daß man das Watcher-Objekt,
193 das der Konstruktor liefert, auch aufbewahrt, denn wenn man es vergisst,
194 wird der Watcher automatisch deaktiviert. Hier kehrt C<EV::loop> sofort
195 zurück, wenn keine sonstigen Watcher aktiv sind, denn der Timer wird
196 erzeugt, gestartet und sofort wieder gelöscht:
197
198 EV::timer 10, 10, sub { };
199 EV::loop;
200
201 I/O-Watcher gehen genauso einfach. Das folgende Beispiel "loop"ed so
202 lange, bis man auf STDIN eine Zeile die mit C<q> beginnt, eingibt (z.b.
203 "quit"):
204
205 my $stdin_watcher = EV::io *STDIN, EV::READ, sub {
206 my $line = <STDIN>;
207
208 # $_[0] enthält das watcher-objekt
209 $_[0]->stop if $line =~ /^q/;
210 };
211
212 EV::loop;
213
214 Alternativ kann man den Watcher auch "einfach" C<undef>'en (die
215 Sichtbarkeit von my-Variablen in Perl macht das ein bißchen eklig):
216
217 my $stdin_watcher;
218 $stdin_watcher = EV::io *STDIN, EV::READ, sub {
219 my $line = <STDIN>;
220
221 undef $stdin_watcher if $line =~ /^q/;
222 };
223
224 EV::loop;
225
226 =head2 Spezialitäten
227
228 Nach dem Standardkram, hier ein paar Spezialitäten, die so wahrscheinlich
229 nur mit EV gehen.
230
231 =over 4
232
233 =item Ein Watcher, der jeden Tag um Mitternacht lokaler Zeit seinen
234 Callback aufruft (genauer: zur nächsten Mitternacht nach 23:59:59 des
235 aktuellen Tages. Für Details muß ich auf die Manpage verweisen):
236
237 use EV;
238 use Time::Local;
239
240 my $geisterstunde = EV::periodic 0, 0, sub {
241 my ($w, $now) = @_;
242
243 # berechne den nächsten Zeitpunkt des "Feuerns":
244 my ($y, $m, $d) = (localtime $now)[5, 4, 3];
245 1 + timelocal 59, 59, 23, $d, $m, $y
246 }, sub {
247 warn "buh!";
248 };
249
250 Der erste Callback berechnet auf Zuruf von EV die nächste Mitternacht.
251 Sollte sich die Systemzeit verändern (z.B. ein paar Jahre zurückfallen),
252 ruft EV den Callback automatisch erneut auf.
253
254 =item Überwache F</var/log/messages> auf Veränderungen (die Größe
255 sollte sich dabei verändern: Wenn auch mtime-Änderungen überwacht werden solle, wird es
256 etwas komplexer, wie in der Manpage beschrieben):
257
258 my $logwatcher = EV::stat "/var/log/messages", 10, sub {
259 warn "/var/log/messages size is now ", ($_[0]->attr)[7];
260 };
261
262 =item Überwachung einer Perl-Variable auf Veränderung zwischen zwei
263 Iterationen der EV-Ereignis-Schleife:
264
265 my $var;
266
267 my $oldval = $var;
268 my $checkvar = EV::prepare sub {
269 if ($oldval ne $var) {
270 warn "variable has changed from $oldval to $var\n";
271 $oldval = $var;
272 }
273 };
274
275 =item Einbetten von Kqueue in ein anderes Backend (z.B. für FreeBSD, Mac
276 OS X), damit man wenigstens Sockets effizient benutzen kann:
277
278 my $socket_loop;
279
280 # Erzeuge eine Kqueue-loop WENN Kqueue unterstützt wird UND NICHT
281 # schon für die Standard-Schleife verwendet wird:
282 if (
283 (EV::backend & (EV::BACKEND_POLL | EV::BACKEND_SELECT))
284 && (EV::supported_backends & EV::embeddable_backends & EV::BACKEND_KQUEUE)
285 ) {
286 $socket_loop = new EV::Loop EV::BACKEND_KQUEUE | EV::FLAG_NOENV;
287 }
288
289 # Ansonsten benutze die Standard-Schleife:
290 $socket_loop ||= EV::default_loop;
291
292 # Erzeuge einen Socket-Watcher:
293 my $watcher = $socket->io ($socket_fh, EV::READ, sub { ... });
294
295 Statt die globalen Konstruktoren in EV zu verwenden kann man sie auch
296 über Methodenaufrufe eines EV::Loop-Objektes erreichen.
297
298 =item Benutzung von EV von XS aus.
299
300 Im Makefile.PL:
301
302 use EV::MakeMaker;
303
304 WriteMakefile (EV::MakeMaker::ev_args (
305 ... normale MakeMaker-Argumente
306 ));
307
308 Im .XS-File:
309
310 #include "EVAPI.h"
311
312 static ev_timer mytimer;
313
314 static void
315 mycb (EV_P_ ev_timer *w, int revents)
316 {
317 // zuerst nach 1s, dann alle 2s
318 }
319
320 ...
321
322 BOOT:
323 I_EV_API ("<modulname>");
324 ev_timer_init (&mytimer, mycb, 1., 2.);
325 ev_timer_start (EV_DEFAULT, &mywatcher);
326
327 =back
328
329
330 =head1 Und wie noch?
331
332 Auf CPAN gibt es einige Module, die sich direkt oder indirekt mit EV beschäftigen.
333
334 =head2 Module, die direkt mit EV in Bezug stehen
335
336 =over 4
337
338 =item EV::ADNS
339
340 Eine Schnittstelle zu libadns, einer asynchronen DNS-Resolver-Bibliothek,
341 die sich in EV integriert. Ein gutes Beispiel, wie man eine "EV-fremde"
342 C-Bibliothek in libev/EV integriert (auf XS-Ebene).
343
344 =item Net::SNMP::EV
345
346 Ein Hack, der die Non-Blocking-Aufrufe des Net::SNMP-Moduls in EV
347 integriert: Net::SNMP unterstützt parallel Anfragen, benutzt aber sein
348 eigenes, internes, Event-Modell. Dieses Modul bildet es auf EV ab.
349
350 Einfaches Laden genügt und schon benutzt Net::SNMP für I/O und Timer das
351 EV-Modul.
352
353 Das Modul ist ein gutes Beispiel dafür, wie man "EV-fremde" Perl-Module
354 in EV integrieren kann (auf Perl-Ebene).
355
356 =item Glib::EV
357
358 Dieses Modul ersetzt das "backend" (normalerweise poll oder select) von
359 Glib (bzw. libglib) durch EV. Dies ist üblicherweise (z.B. wenn man
360 epoll verwendet) etwas langsamer als Glib selbst, wenn man jedoch wenige
361 Glib-Watcher (z.B. nur die von Gtk+) und viele (also mehr als 1-2 :)
362 EV-Watcher verwendet, ergibt dies einen Nettogewinn, vor allem, weil Glib
363 die ineffizienteste Implementation eines Event-Modells ist, die ich je
364 gesehen habe.
365
366 Laden des Moduls genügt, man muss jedoch die Hauptschleife von Glib
367 oder Gtk+ benutzen, C<EV::loop> hilft nicht viel, da Glib die Kontrolle
368 behalten muss.
369
370 Arbeitet ähnlich wie EV::ADNS, ist aber komplexer.
371
372 =item EV::Glib
373
374 Mit diesem Modul kann man EV-Watcher in bestehenden Glib-Programmen
375 benutzen.
376
377 Fast identisch mit Glib::EV, jedoch wird hier der "MainContext" von Glib
378 in EV integriert, d.h. die Watcher von Glib werden bei Iterationen von EV
379 mitgeprüft. Dies ist genauso ineffizient wie C<Glib::EV>, es amortisiert
380 sich aber sobald man einige EV-Watcher benutzt.
381
382 Laden des Moduls genügt, man muss jedoch die Hauptschleife von EV
383 aufrufen, was dazu führt, daß sowohl die EV-eigenen als auch die
384 Glib-eigenen Watcher betreut/abgefragt werden.
385
386 Mit diesem Modul kann man Glib (doer Gtk) in einem EV-Programm benutzen.
387
388 =item POE::Loop::EV
389
390 Offenbar ein Backend zu EV von POE. Hab's nicht ausprobiert, die Kerle
391 sollten aber AnyEvent benutzen, damit kriegen sie automatisch EV und alles
392 andere was AnyEvent unterstützt.
393
394 =back
395
396 =head2 Module, die EV benutzen können
397
398 =over 4
399
400 =item AnyEvent
401
402 AnyEvent unterstützt C<EV> (und C<Coro::EV>) explizit, d.h. bestehende
403 Anwender von AnyEvent kommen sofort in den Genuß von EV.
404
405 AnyEvent + EV ist sogar schneller als die meisten (bzw. alle von mir
406 getesteten) Event-Module, und das, obwohl AnyEvent vergleichsweise viel
407 Aufwand leisten muss.
408
409 =item Coro, Coro::EV
410
411 Die Filehandle- und Timer-Abstraktionen von C<Coro> (C<Coro::Handle>,
412 C<Coro::Socket>, C<Coro::Timer>) unterstützen EV direkt (über
413 C<Coro::EV>). EV ist das effizienteste direkt unterstützte Event-Modul in
414 C<Coro::Coro>.
415
416 C<Coro::EV> hat neben der Unterstützung von C<Coro::Handle> noch
417 Hilfsfunktionen, um einmalige Verzögerungen u.ä. in Coroutinen zu
418 benutzen.
419
420 Sollte C<EV::ADNS> installiert sein, so wird es von C<Coro::Util> (und
421 damit auch C<Coro::Socket>) für DNS-Anfragen benutzt, statt einen
422 separaten Prozess zu forken (was sehr langsam sein kann).
423
424 =item IO::AIO / Coro::AIO
425
426 Haben direkt nichts mit EV zu tun (außer, daß sie mit EV gut
427 funktionieren), aber für jedes ereignisgesteuerte Programm ein Muss, da
428 man damit ereignisgesteuert (und asynchron) auf das Dateisystem zugreifen
429 kann, mit Coro::AIO sogar ähnlich einfach wie mit den eingebauten
430 Perl-Funktionen.
431
432 =item BDB / Coro::BDB
433
434 Was IO::AIO für's Dateisystem ist, ist BDB für die Berkeley DB, nämlich
435 ein Modul, mit dem man ereignisgesteuert die Berkeley DB benutzen kann.
436
437 =back
438
439 =head2 Werbung
440
441 Ok, pure Werbung, aber es gibt noch andere Programme, die Libev benutzen.
442
443 =over 4
444
445 =item GVPE, das GNU Virtual Private Ethernet
446
447 In der nächsten (2.2) Release wird es Libev benutzen. Bringt total viel :->
448
449 http://savannah.gnu.org/projects/gvpe
450
451 =item Rxvt-Unicode
452
453 Das allerbeste Terminal überhaupt, vor allem, weil es einen
454 Perl-Interpreter embeddet. Und dazu benutzt es (ab Version 8.4 oder so)
455 auch Libev. Leider ohne EV, sondern mit eigener Perl-Schnittstelle, aber
456 na gut, man kann nicht alles haben.
457
458 http://software.schmorp.de/pkg/rxvt-unicode.html
459
460 =item Deliantra
461
462 Das allergeilste Online-RPG wo gibt, vor allem, weil es Perl embeddet,
463 einen ganzen vollen Interpreter. Nicht nur, es benutzt auch Coro, IO::AIO,
464 BDB uvm., und der OpenGL-supergeile-Grafik-mach-Client ist ebenfalls
465 in Perl geschrieben und benutzt EV, BDB... den Rest kann man sich
466 vorstellen. Ein Must-See-Must-Have, vor allem wegen des super Retro-Stils!
467
468 http://www.deliantra.net/
469
470 =item OpenMPI
471
472 Wird, nach eigener Aussage, in der nächsten Release ebenfalls Libev
473 benutzen. Kein embeddetes Perl in Sicht.
474
475 http://www.openmpi.org/
476
477 =back
478
479
480 =head1 Hä?
481
482 Ich kann (bzw. wollte) hier nur eine kurze Übersicht geben bzw. einen
483 Geschmack vermitteln und eventuell neugierig machen.
484
485 Mehr Informationen gibt es auf der libev-Manpage:
486
487 http://libev.schmorp.de/
488
489 Von dort gibt es auch einen Link zu EV (der Perl-Schnittstelle), dessen
490 Doku, und einem Benchmark mit Libevent:
491
492 http://pod.tst.eu/http://cvs.schmorp.de/EV/EV.pm
493 http://pod.tst.eu/http://cvs.schmorp.de/libev/ev.pod
494 http://libev.schmorp.de/bench.html
495
496 =head1 Autor
497
498 Marc Lehmann <schmorp@schmorp.de>.