ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/cvsroot/docs/ev.pod
Revision: 1.1
Committed: Mon Jan 7 23:10:19 2008 UTC (18 years, 8 months ago) by root
Branch: MAIN
Log Message:
*** empty log message ***

File Contents

# User Rev Content
1 root 1.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