ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/cvsroot/docs/ev.pod
Revision: 1.13
Committed: Wed Jan 16 02:59:25 2008 UTC (18 years, 8 months ago) by root
Branch: MAIN
CVS Tags: HEAD
Changes since 1.12: +7 -0 lines
Log Message:
*** empty log message ***

File Contents

# Content
1 =head1 EV - (noch) ein Event-Modell für Perl
2
3 =head1 Was?
4
5 EV ist ein Perl-Modul, das Ereignisgesteuertes Programmieren
6 unterstützt. Darin unterscheidet es sich erst einmal nicht von anderen
7 dedizierten Modulen wie "Event" oder die in jedes Toolkit (Gtk, Tk etc.)
8 eingebaute Ereignisverarbeitung.
9
10 EV ist des weiteren eine Schnittstelle zur "Libev"-Bibliothek, eine Art
11 Libevent-Klon, und erbt deshalb deren Features (worin sich EV nun von
12 einigen anderen Modulen unterscheidet):
13
14 =over 4
15
16 =item Korrektheit
17
18 Die meisten Ereignis-Bibliotheken funktionieren gut, solange nichts
19 unvorhergesehenes passiert.
20
21 Die meisten versagen kläglich, wenn die Systemuhr verstellt wird
22 (Zeitsprünge): Aus einem 10s-Timeout können bei Tk (Event, Glib etc.)
23 problemlos mal Jahre werden, aus einem Tag wenige Sekunden. EV unterstützt
24 sowohl relative Timer ("wecke mich in 10 Minuten auf, egal ob ntpd die
25 Uhr ändert oder nicht) als auch absolute Timer ("wecke mich 2008-10-10
26 12:17:23.445 auf, egal wie lange das wirklich dauert" oder gar "wecke
27 mich zur nächsten Mitternacht auf"), was kein anderes mir bekanntes
28 Event-Modell unterstützt.
29
30 Registriert man bei Tk (Event::Lib, ...) zwei Watcher auf denselben
31 Filehandle, so kann einer davon verloren gehen (nicht notwendigerweise
32 immer der ältere oder neuere).
33
34 Stellt man bei Event die "richtigen" Prioritäten ein, kriegt man eine
35 stetig wachsende Event-Queue die nicht kleiner wird (was allerdings selten
36 in Out-Of-Memory-Situationen endet, denn Event wird vorher zu langsam).
37
38 Das alles sind Kleinigkeiten - bis das Programm deshalb mal "hängt", 100%
39 Rechenzeit verbraucht oder gar sporadisch versagt.
40
41 Außerdem haben viele Event-Modelle (Event, Glib, Tk...) ein von Perl
42 abweichendes Objektmodell: verliert man beim Event oder Glib die Referenz
43 auf den Watcher, so hat man bestenfalls ein Memory-Leak. Die EV-Watcher
44 bestehen genau so lange, wie Referenzen darauf zeigen wie jedes andere
45 Perl-Objekt auch.
46
47 Fork ist ein ganz spezielles Problem: wenige Event-Bibliotheken
48 unterstützen es direkt, vor allem diejenigen, die Epoll, Kqueue
49 o.ä. benutzen, da diese Schnittstellen sehr fork-feindlich sind. EV
50 unterstützt fork indem es den Kernel-Zustand im Kindprozess automatisch
51 wiederherstellt, sofern es benutzt wird.
52
53 =item Geschwindigkeit
54
55 EV benutzt "die richtigen" Algorithmen zur Verwaltung: Heaps für die
56 Verwaltung der Timer (keine lineare Liste oder ähnliches wie alle
57 anderen), Arrays, wenn es um viele Watcher geht, Listen, wenn es nur
58 wenige (meist einen) geht. Auch geht Libev nicht vor jedem Pollen alle
59 seine Watcher (Event, Glib, ...) durch um zu sehen ob sie noch alle da
60 sind.
61
62 Dadurch skaliert EV nicht nur hervorragend in die Bereiche von
63 hunderttausenden Filehandles und Timern (falls man das braucht), sondern
64 ist auch mit wenigen davon sehr schnell (was mindstens genauso wichtig
65 ist).
66
67 Auch die Perl-Schnittstelle selbst wurde geschrieben, um unnötige
68 Laufzeitkosten zu vermeiden: EV erzeugt einen Watcher immerhin 40 mal
69 schneller als Event und fast viermal so schnell wie Glib, womit EV +
70 AnyEvent immer noch schneller sind als "nacktes" Glib.
71
72 Auch der Speicherverbrauch ist sehr gering: EV-Watcher sind schlichte
73 geblesste Strings die den Libev-Watcher enthalten. Diese wiederum sind im
74 Vergleich mit anderen Bibliotheken recht klein (weniger als 100 Bytes).
75
76 =item Skalierbarkeit
77
78 Nicht nur die Algorithmen, auch die Schnittstelle zum Betriebssystem muss
79 skalierbar sein, und das bedeutet leider auch: nicht portabel. Jedes
80 Betriebssystem braucht sein eigenes Rezept und daher auch sein eigenes
81 Backend: Libev unterstützt Epoll, Kqueue und Solaris' Event Ports.
82
83 Einige Backends sind sehr begrenzt (Kqueue z.B. ist auf fast allen System
84 kaputt und supported bestenfalls Sockets) aber in andere Backends
85 integrierbar, so kann man z.B. ein Kqueue-Backend (supported nur Sockets
86 zuverlässig auf FreeBSD) in ein "herkömmliches" Poll-basiertes Backend
87 integrieren.
88
89 =item Watcher-Typen
90
91 Neben den üblichen I/O Watchern und Timern (derer es zwei grundsätzlich
92 verschiedene Typen in EV gibt), bietet EV noch speziellere
93 Watchertypen für POSIX-Signale, Prozess-Watcher, Idle-Watcher (für
94 "Hintergrundprozesse"), Prepare/Check-Watcher, mit denen man EV-fremde
95 Event-Modelle oder -Benutzer integrieren kann und Stat-Watcher, mit denen
96 man Dateisystemobjekte auf Veränderungen überwachen kann. Ganz spezielle
97 Watcher, um C<fork()> zu erkennen oder andere Backends zu integrieren gibt
98 es natürlich auch.
99
100 =item Kompatibilität
101
102 EV wird von AnyEvent voll unterstützt, so daß Module oder Programme, die
103 AnyEvent benutzen, ohne Quellcodeänderungen sofort mit EV benutzt werden
104 können.
105
106 =item C-Schnittstelle
107
108 Das EV-Modul exportiert die komplette Libev-API auch auf XS-Ebene, was
109 so nur noch Event bietet (bei anderen Modulen muss man auf positive
110 Eigenschaften von Shared-Libraries vertrauen).
111
112 =back
113
114
115 =head1 Warum?
116
117 EV ist, wie die zugrunde liegende Libev, sehr jung (Ende 2007 erschien
118 die erste Version), und die Entstehung war mehr Zufall als Absicht: Seit
119 ca. 1998 benutze ich regelmäßig und viel das Event-Modul, welches
120 problemlos als das ausgereifteste der verfügbaren Event-Module gelten
121 durfte.
122
123 Im Laufe der Jahre stieß ich auf eine Menge kleinerer Probleme mit anderen
124 Event-Modellen (siehe weiter oben), doch die Anstrengung, eine eigene
125 Bibliothek zu schreiben, wollte ich nicht aufbringen.
126
127 Speicherverbrauch war eigentlich nie ein Problem, die Beschränkung auf
128 C<select> und C<poll> schon eher, aber man hat ja schnelle Rechner die
129 das kompensieren (und wenn man nicht drauf achtet, was die Rechenzeit
130 verbraucht, stört es ja sowieso nie).
131
132 An die echten Fehler in z.B. Event gewöhnt man sich mit der Zeit, bzw.
133 findet mehr oder weniger akzeptable Umleitungen um das Problem, oder
134 vermeidet den Einsatz in solchen Fällen ganz.
135
136 Eines Tages kam jedoch die Notwendigkeit, wirklich viele Filehandles
137 effizient zu verwalten, und da Libevent sowas wie der Standard für
138 Performance zu sein schien und es dafür keine Perl-Schnittstelle gab
139 (das ist falsch, es gab eine, nämlich C<Event::Lib>, aber ich habe sie
140 trotz suchens auf CPAN nicht wahrgenommen), fing' ich an, eine eigene
141 Schnittstelle zu Libevent zu schreiben.
142
143 Wenig erfreut war ich, als ich herausfand, daß Libevent die gleichen
144 Probleme wie Tk hat (nicht mehrere Watcher auf einem Filehandle) und auch
145 nicht wenige Schwächen in der API. Das Erlebnis war derart frustrierend,
146 daß ich mich entschieden habe, endgültig 'mein eigenes Ding' zu machen. Wie
147 erwartet, war es mehr Arbeit, als ich eigentlich investieren wollte,
148 aber nach einigen Monaten hatte ich etwas gebrauchsfähiges, daß sogar
149 bei Benchmarks gegenüber dem "Standard" (nämlich Libevent) hervorragend
150 abschneidet.
151
152 Da die meisten meiner Module AnyEvent benutzen, und die API von EV (im
153 Geiste...) der von Event ähnelt, war die Umstellung aller meiner wichtigen
154 Projekte (gvpe, rxvt-unicode, Deliantra, mein Webserver sowie mehrere
155 kommerzielle Anwendungen) kein Problem, was natürlich ein sehr guter Test
156 für das Modul war (und ist).
157
158 EV ist somit das Ergebnis von knapp 10 Jahren Erfahrung mit
159 anderen Event-Modellen, deren Stärken und Schwächen und deren
160 Perl-Schnittstelle: alle mir bekannten Probleme wurden adresssiert.
161
162
163 =head1 Wie?
164
165 Nach so viel Blabla wird's Zeit für Code-Beispiele.
166
167 Einen langweiligen Timer realisiert man so.
168
169 use EV;
170
171 my $timer = EV::timer 1, 2, sub {
172 warn "zeitstempel: " . EV::now;
173 warn "man rief' mich auf nach 1s dann alle 2s. yeah.";
174 };
175
176 EV::loop;
177
178 Das gibt nach einer Sekunde ein warn, und danach alle zwei Sekunden, bis
179 in alle Ewigkeit/Reset/SIGINT etc.
180
181 EV::loop kehrt automatisch zurück, wenn es keine aktiven Watcher mehr gibt
182 (das nennt man "Deadlock"):
183
184 my $delay = EV::timer 1, 0, sub {
185 warn "nur einmal nach 1s werde ich aufgerufen.\n";
186 };
187
188 EV::loop;
189
190 Das läuft nur für eine Sekunde. Wichtig ist, daß man das Watcher-Objekt,
191 das der Konstruktor liefert, auch aufbewahrt, denn wenn man es vergisst,
192 wird der Watcher automatisch deaktiviert. Hier kehrt C<EV::loop> sofort
193 zurück, wenn keine sonstigen Watcher aktiv sind, denn der Timer wird
194 erzeugt, gestartet und sofort wieder gelöscht:
195
196 EV::timer 10, 10, sub { };
197 EV::loop;
198
199 I/O-Watcher gehen genauso einfach. Das folgende Beispiel "loop"ed so
200 lange, bis man auf STDIN eine Zeile die mit C<q> beginnt, eingibt (z.b.
201 "quit"):
202
203 my $stdin_watcher = EV::io *STDIN, EV::READ, sub {
204 my $line = <STDIN>;
205
206 # $_[0] enthält das watcher-objekt
207 $_[0]->stop if $line =~ /^q/;
208 };
209
210 EV::loop;
211
212 Alternativ kann man den Watcher auch "einfach" C<undef>'en (die
213 Sichtbarkeit von my-Variablen in Perl macht das ein bißchen eklig):
214
215 my $stdin_watcher;
216 $stdin_watcher = EV::io *STDIN, EV::READ, sub {
217 my $line = <STDIN>;
218
219 undef $stdin_watcher if $line =~ /^q/;
220 };
221
222 EV::loop;
223
224 =head2 Spezialitäten
225
226 Nach dem Standardkram, hier ein paar Spezialitäten, die so wahrscheinlich
227 nur mit EV gehen.
228
229 =over 4
230
231 =item Ein Watcher, der jeden Tag um Mitternacht lokaler Zeit seinen
232 Callback aufruft (genauer: zur nächsten Mitternacht nach 23:59:59 des
233 aktuellen Tages. Für Details muß ich auf die Manpage verweisen):
234
235 use EV;
236 use Time::Local;
237
238 my $geisterstunde = EV::periodic 0, 0, sub {
239 my ($w, $now) = @_;
240
241 # berechne den nächsten Zeitpunkt des "Feuerns":
242 my ($y, $m, $d) = (localtime $now)[5, 4, 3];
243 1 + timelocal 59, 59, 23, $d, $m, $y
244 }, sub {
245 warn "buh!";
246 };
247
248 Der erste Callback berechnet auf Zuruf von EV die nächste Mitternacht.
249 Sollte sich die Systemzeit verändern (z.B. ein paar Jahre zurückfallen),
250 ruft EV den Callback automatisch erneut auf.
251
252 =item Überwache F</var/log/messages> auf Veränderungen (die Größe
253 sollte sich dabei verändern: Wenn auch mtime-Änderungen überwacht werden solle, wird es
254 etwas komplexer, wie in der Manpage beschrieben):
255
256 my $logwatcher = EV::stat "/var/log/messages", 10, sub {
257 warn "/var/log/messages size is now ", ($_[0]->attr)[7];
258 };
259
260 =item Überwachung einer Perl-Variable auf Veränderung zwischen zwei
261 Iterationen der EV-Ereignis-Schleife:
262
263 my $var;
264
265 my $oldval = $var;
266 my $checkvar = EV::prepare sub {
267 if ($oldval ne $var) {
268 warn "variable has changed from $oldval to $var\n";
269 $oldval = $var;
270 }
271 };
272
273 Ein C<prepare>-Watcher wird ausgeführt bevor EV nach neuen Ereignissen
274 Ausschau hält, während ein C<check>-Watcher direkt danach ausgeführt
275 wird. Auf diese Weise kann man EV-fremde Ereignisse in EV integrieren,
276 z.B. kann man in einem C<prepare>-Watcher neue Watcher erzeugen für z.B.
277 die Sockets von C<Net::SNMP> während man in einem C<check>-Watcher dann
278 auf entsprechende Ereignisse reagieren kann.
279
280 =item Einbetten von Kqueue in ein anderes Backend (z.B. für FreeBSD, Mac
281 OS X), damit man wenigstens Sockets effizient benutzen kann:
282
283 my $socket_loop;
284
285 # Erzeuge eine Kqueue-loop WENN Kqueue unterstützt wird UND NICHT
286 # schon für die Standard-Schleife verwendet wird:
287 if (
288 (EV::backend & (EV::BACKEND_POLL | EV::BACKEND_SELECT))
289 && (EV::supported_backends & EV::embeddable_backends & EV::BACKEND_KQUEUE)
290 ) {
291 $socket_loop = new EV::Loop EV::BACKEND_KQUEUE | EV::FLAG_NOENV;
292 }
293
294 # Ansonsten benutze die Standard-Schleife:
295 $socket_loop ||= EV::default_loop;
296
297 # Erzeuge einen Socket-Watcher:
298 my $watcher = $socket->io ($socket_fh, EV::READ, sub { ... });
299
300 Statt die globalen Konstruktoren in EV zu verwenden kann man sie auch
301 über Methodenaufrufe eines EV::Loop-Objektes erreichen.
302
303 =item Benutzung von EV von XS aus.
304
305 Im Makefile.PL:
306
307 use EV::MakeMaker;
308
309 WriteMakefile (EV::MakeMaker::ev_args (
310 ... normale MakeMaker-Argumente
311 ));
312
313 Im .XS-File:
314
315 #include "EVAPI.h"
316
317 static ev_timer mytimer;
318
319 static void
320 mycb (EV_P_ ev_timer *w, int revents)
321 {
322 // zuerst nach 1s, dann alle 2s
323 }
324
325 ...
326
327 BOOT:
328 I_EV_API ("<modulname>");
329 ev_timer_init (&mytimer, mycb, 1., 2.);
330 ev_timer_start (EV_DEFAULT, &mywatcher);
331
332 =back
333
334
335 =head1 Und wie noch?
336
337 Auf CPAN gibt es einige Module, die sich direkt oder indirekt mit EV beschäftigen.
338
339 =head2 Module, die direkt mit EV in Bezug stehen
340
341 =over 4
342
343 =item EV::ADNS
344
345 Eine Schnittstelle zu libadns, einer asynchronen DNS-Resolver-Bibliothek,
346 die sich in EV integriert. Ein gutes Beispiel, wie man eine "EV-fremde"
347 C-Bibliothek in libev/EV integriert (auf XS-Ebene).
348
349 =item Net::SNMP::EV
350
351 Ein Hack, der die Non-Blocking-Aufrufe des Net::SNMP-Moduls in EV
352 integriert: Net::SNMP unterstützt parallel Anfragen, benutzt aber sein
353 eigenes, internes, Event-Modell. Dieses Modul bildet es auf EV ab.
354
355 Einfaches Laden genügt und schon benutzt Net::SNMP für I/O und Timer das
356 EV-Modul.
357
358 Das Modul ist ein gutes Beispiel dafür, wie man "EV-fremde" Perl-Module
359 in EV integrieren kann (auf Perl-Ebene).
360
361 =item Glib::EV
362
363 Dieses Modul ersetzt das "backend" (normalerweise poll oder select) von
364 Glib (bzw. libglib) durch EV. Dies ist üblicherweise (z.B. wenn man
365 epoll verwendet) etwas langsamer als Glib selbst, wenn man jedoch wenige
366 Glib-Watcher (z.B. nur die von Gtk+) und viele (also mehr als 1-2 :)
367 EV-Watcher verwendet, ergibt dies einen Nettogewinn, vor allem, weil Glib
368 die ineffizienteste Implementation eines Event-Modells ist, die ich je
369 gesehen habe.
370
371 Laden des Moduls genügt, man muss jedoch die Hauptschleife von Glib
372 oder Gtk+ benutzen, C<EV::loop> hilft nicht viel, da Glib die Kontrolle
373 behalten muss.
374
375 Arbeitet ähnlich wie EV::ADNS, ist aber komplexer.
376
377 =item EV::Glib
378
379 Mit diesem Modul kann man EV-Watcher in bestehenden Glib-Programmen
380 benutzen.
381
382 Fast identisch mit Glib::EV, jedoch wird hier der "MainContext" von Glib
383 in EV integriert, d.h. die Watcher von Glib werden bei Iterationen von EV
384 mitgeprüft. Dies ist genauso ineffizient wie C<Glib::EV>, es amortisiert
385 sich aber sobald man einige EV-Watcher benutzt.
386
387 Laden des Moduls genügt, man muss jedoch die Hauptschleife von EV
388 aufrufen, was dazu führt, daß sowohl die EV-eigenen als auch die
389 Glib-eigenen Watcher betreut/abgefragt werden.
390
391 Mit diesem Modul kann man Glib (doer Gtk) in einem EV-Programm benutzen.
392
393 =item POE::Loop::EV
394
395 Offenbar ein Backend zu EV von POE. Hab's nicht ausprobiert, die Kerle
396 sollten aber AnyEvent benutzen, damit kriegen sie automatisch EV und alles
397 andere was AnyEvent unterstützt.
398
399 =back
400
401 =head2 Module, die EV benutzen können
402
403 =over 4
404
405 =item AnyEvent
406
407 AnyEvent unterstützt C<EV> (und C<Coro::EV>) explizit, d.h. bestehende
408 Anwender von AnyEvent kommen sofort in den Genuß von EV.
409
410 AnyEvent + EV ist sogar schneller als die meisten (bzw. alle von mir
411 getesteten) Event-Module, und das, obwohl AnyEvent vergleichsweise viel
412 Aufwand leisten muss.
413
414 =item Coro, Coro::EV
415
416 Die Filehandle- und Timer-Abstraktionen von C<Coro> (C<Coro::Handle>,
417 C<Coro::Socket>, C<Coro::Timer>) unterstützen EV direkt (über
418 C<Coro::EV>). EV ist das effizienteste direkt unterstützte Event-Modul in
419 C<Coro>.
420
421 C<Coro::EV> hat neben der Unterstützung von C<Coro::Handle> noch
422 Hilfsfunktionen, um einmalige Verzögerungen u.ä. in Coroutinen zu
423 benutzen.
424
425 Sollte C<EV::ADNS> installiert sein, so wird es von C<Coro::Util> (und
426 damit auch C<Coro::Socket>) für DNS-Anfragen benutzt, statt einen
427 separaten Prozess zu forken (was sehr langsam sein kann).
428
429 =item IO::AIO / Coro::AIO
430
431 Haben direkt nichts mit EV zu tun (außer, daß sie mit EV gut
432 funktionieren), aber für jedes ereignisgesteuerte Programm ein Muss, da
433 man damit ereignisgesteuert (und asynchron) auf das Dateisystem zugreifen
434 kann, mit Coro::AIO sogar ähnlich einfach wie mit den eingebauten
435 Perl-Funktionen.
436
437 =item BDB / Coro::BDB
438
439 Was IO::AIO für's Dateisystem ist, ist BDB für die Berkeley DB, nämlich
440 ein Modul, mit dem man ereignisgesteuert die Berkeley DB benutzen kann.
441
442 =back
443
444 =head2 Werbung
445
446 Ok, pure Werbung, aber es gibt noch andere Programme, die Libev benutzen.
447
448 =over 4
449
450 =item GVPE, das GNU Virtual Private Ethernet
451
452 In der nächsten (2.2) Release wird es Libev benutzen. Bringt total viel :->
453
454 http://savannah.gnu.org/projects/gvpe
455
456 =item Rxvt-Unicode
457
458 Das allerbeste Terminal überhaupt, vor allem, weil es einen
459 Perl-Interpreter embeddet. Und dazu benutzt es (ab Version 8.4 oder so)
460 auch Libev. Leider ohne EV, sondern mit eigener Perl-Schnittstelle, aber
461 na gut, man kann nicht alles haben.
462
463 http://software.schmorp.de/pkg/rxvt-unicode.html
464
465 =item Deliantra
466
467 Das allergeilste Online-RPG wo gibt, vor allem, weil es Perl embeddet,
468 einen ganzen vollen Interpreter. Nicht nur, es benutzt auch Coro, IO::AIO,
469 BDB uvm., und der OpenGL-supergeile-Grafik-mach-Client ist ebenfalls
470 in Perl geschrieben und benutzt EV, BDB... den Rest kann man sich
471 vorstellen. Ein Must-See-Must-Have, vor allem wegen des super Retro-Stils!
472
473 http://www.deliantra.net/
474
475 =item OpenMPI
476
477 Wird, nach eigener Aussage, in der nächsten Release ebenfalls Libev
478 benutzen. Kein embeddetes Perl in Sicht.
479
480 http://www.openmpi.org/
481
482 =back
483
484
485 =head1 Hä?
486
487 Ich kann (bzw. wollte) hier nur eine kurze Übersicht geben bzw. einen
488 Geschmack vermitteln und eventuell neugierig machen.
489
490 Mehr Informationen gibt es auf der libev-Manpage:
491
492 http://libev.schmorp.de/
493
494 Von dort gibt es auch einen Link zu EV (der Perl-Schnittstelle), dessen
495 Doku, und einem Benchmark mit Libevent:
496
497 http://pod.tst.eu/http://cvs.schmorp.de/EV/EV.pm
498 http://pod.tst.eu/http://cvs.schmorp.de/libev/ev.pod
499 http://libev.schmorp.de/bench.html
500
501 =head1 Autor
502
503 Marc Lehmann <schmorp@schmorp.de>.