| 1 |
root |
1.12 |
=head1 EV - (noch) ein Event-Modell für Perl |
| 2 |
root |
1.1 |
|
| 3 |
|
|
=head1 Was? |
| 4 |
|
|
|
| 5 |
|
|
EV ist ein Perl-Modul, das Ereignisgesteuertes Programmieren |
| 6 |
root |
1.2 |
unterstützt. Darin unterscheidet es sich erst einmal nicht von anderen |
| 7 |
root |
1.1 |
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 |
root |
1.3 |
=item Korrektheit |
| 17 |
root |
1.1 |
|
| 18 |
|
|
Die meisten Ereignis-Bibliotheken funktionieren gut, solange nichts |
| 19 |
|
|
unvorhergesehenes passiert. |
| 20 |
|
|
|
| 21 |
root |
1.2 |
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 |
root |
1.1 |
sowohl relative Timer ("wecke mich in 10 Minuten auf, egal ob ntpd die |
| 25 |
root |
1.2 |
Uhr ändert oder nicht) als auch absolute Timer ("wecke mich 2008-10-10 |
| 26 |
root |
1.1 |
12:17:23.445 auf, egal wie lange das wirklich dauert" oder gar "wecke |
| 27 |
root |
1.2 |
mich zur nächsten Mitternacht auf"), was kein anderes mir bekanntes |
| 28 |
|
|
Event-Modell unterstützt. |
| 29 |
root |
1.1 |
|
| 30 |
|
|
Registriert man bei Tk (Event::Lib, ...) zwei Watcher auf denselben |
| 31 |
|
|
Filehandle, so kann einer davon verloren gehen (nicht notwendigerweise |
| 32 |
root |
1.2 |
immer der ältere oder neuere). |
| 33 |
root |
1.1 |
|
| 34 |
root |
1.2 |
Stellt man bei Event die "richtigen" Prioritäten ein, kriegt man eine |
| 35 |
root |
1.1 |
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 |
root |
1.2 |
Das alles sind Kleinigkeiten - bis das Programm deshalb mal "hängt", 100% |
| 39 |
root |
1.1 |
Rechenzeit verbraucht oder gar sporadisch versagt. |
| 40 |
|
|
|
| 41 |
root |
1.2 |
Außerdem haben viele Event-Modelle (Event, Glib, Tk...) ein von Perl |
| 42 |
root |
1.1 |
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 |
root |
1.2 |
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 |
root |
1.1 |
wiederherstellt, sofern es benutzt wird. |
| 52 |
|
|
|
| 53 |
root |
1.3 |
=item Geschwindigkeit |
| 54 |
root |
1.1 |
|
| 55 |
root |
1.2 |
EV benutzt "die richtigen" Algorithmen zur Verwaltung: Heaps für die |
| 56 |
|
|
Verwaltung der Timer (keine lineare Liste oder ähnliches wie alle |
| 57 |
root |
1.1 |
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 |
root |
1.2 |
Auch die Perl-Schnittstelle selbst wurde geschrieben, um unnötige |
| 68 |
root |
1.1 |
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 |
root |
1.3 |
=item Skalierbarkeit |
| 77 |
root |
1.1 |
|
| 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 |
root |
1.2 |
Backend: Libev unterstützt Epoll, Kqueue und Solaris' Event Ports. |
| 82 |
root |
1.1 |
|
| 83 |
|
|
Einige Backends sind sehr begrenzt (Kqueue z.B. ist auf fast allen System |
| 84 |
root |
1.9 |
kaputt und supported bestenfalls Sockets) aber in andere Backends |
| 85 |
root |
1.1 |
integrierbar, so kann man z.B. ein Kqueue-Backend (supported nur Sockets |
| 86 |
root |
1.2 |
zuverlässig auf FreeBSD) in ein "herkömmliches" Poll-basiertes Backend |
| 87 |
root |
1.1 |
integrieren. |
| 88 |
|
|
|
| 89 |
root |
1.3 |
=item Watcher-Typen |
| 90 |
root |
1.1 |
|
| 91 |
root |
1.2 |
Neben den üblichen I/O Watchern und Timern (derer es zwei grundsätzlich |
| 92 |
root |
1.1 |
verschiedene Typen in EV gibt), bietet EV noch speziellere |
| 93 |
root |
1.2 |
Watchertypen für POSIX-Signale, Prozess-Watcher, Idle-Watcher (für |
| 94 |
root |
1.1 |
"Hintergrundprozesse"), Prepare/Check-Watcher, mit denen man EV-fremde |
| 95 |
|
|
Event-Modelle oder -Benutzer integrieren kann und Stat-Watcher, mit denen |
| 96 |
root |
1.2 |
man Dateisystemobjekte auf Veränderungen überwachen kann. Ganz spezielle |
| 97 |
root |
1.1 |
Watcher, um C<fork()> zu erkennen oder andere Backends zu integrieren gibt |
| 98 |
root |
1.2 |
es natürlich auch. |
| 99 |
root |
1.1 |
|
| 100 |
root |
1.3 |
=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 |
root |
1.1 |
|
| 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 |
root |
1.2 |
ca. 1998 benutze ich regelmäßig und viel das Event-Modul, welches |
| 120 |
|
|
problemlos als das ausgereifteste der verfügbaren Event-Module gelten |
| 121 |
root |
1.1 |
durfte. |
| 122 |
|
|
|
| 123 |
root |
1.2 |
Im Laufe der Jahre stieß ich auf eine Menge kleinerer Probleme mit anderen |
| 124 |
root |
1.1 |
Event-Modellen (siehe weiter oben), doch die Anstrengung, eine eigene |
| 125 |
|
|
Bibliothek zu schreiben, wollte ich nicht aufbringen. |
| 126 |
|
|
|
| 127 |
root |
1.2 |
Speicherverbrauch war eigentlich nie ein Problem, die Beschränkung auf |
| 128 |
root |
1.1 |
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 |
root |
1.2 |
verbraucht, stört es ja sowieso nie). |
| 131 |
root |
1.1 |
|
| 132 |
root |
1.2 |
An die echten Fehler in z.B. Event gewöhnt man sich mit der Zeit, bzw. |
| 133 |
root |
1.1 |
findet mehr oder weniger akzeptable Umleitungen um das Problem, oder |
| 134 |
root |
1.2 |
vermeidet den Einsatz in solchen Fällen ganz. |
| 135 |
root |
1.1 |
|
| 136 |
|
|
Eines Tages kam jedoch die Notwendigkeit, wirklich viele Filehandles |
| 137 |
root |
1.2 |
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 |
root |
1.1 |
trotz suchens auf CPAN nicht wahrgenommen), fing' ich an, eine eigene |
| 141 |
|
|
Schnittstelle zu Libevent zu schreiben. |
| 142 |
|
|
|
| 143 |
root |
1.2 |
Wenig erfreut war ich, als ich herausfand, daß Libevent die gleichen |
| 144 |
root |
1.1 |
Probleme wie Tk hat (nicht mehrere Watcher auf einem Filehandle) und auch |
| 145 |
root |
1.2 |
nicht wenige Schwächen in der API. Das Erlebnis war derart frustrierend, |
| 146 |
root |
1.9 |
daß ich mich entschieden habe, endgültig 'mein eigenes Ding' zu machen. Wie |
| 147 |
root |
1.1 |
erwartet, war es mehr Arbeit, als ich eigentlich investieren wollte, |
| 148 |
root |
1.2 |
aber nach einigen Monaten hatte ich etwas gebrauchsfähiges, daß sogar |
| 149 |
|
|
bei Benchmarks gegenüber dem "Standard" (nämlich Libevent) hervorragend |
| 150 |
root |
1.1 |
abschneidet. |
| 151 |
|
|
|
| 152 |
|
|
Da die meisten meiner Module AnyEvent benutzen, und die API von EV (im |
| 153 |
root |
1.2 |
Geiste...) der von Event ähnelt, war die Umstellung aller meiner wichtigen |
| 154 |
root |
1.1 |
Projekte (gvpe, rxvt-unicode, Deliantra, mein Webserver sowie mehrere |
| 155 |
root |
1.2 |
kommerzielle Anwendungen) kein Problem, was natürlich ein sehr guter Test |
| 156 |
|
|
für das Modul war (und ist). |
| 157 |
root |
1.1 |
|
| 158 |
|
|
EV ist somit das Ergebnis von knapp 10 Jahren Erfahrung mit |
| 159 |
root |
1.2 |
anderen Event-Modellen, deren Stärken und Schwächen und deren |
| 160 |
root |
1.1 |
Perl-Schnittstelle: alle mir bekannten Probleme wurden adresssiert. |
| 161 |
|
|
|
| 162 |
|
|
|
| 163 |
|
|
=head1 Wie? |
| 164 |
|
|
|
| 165 |
root |
1.3 |
Nach so viel Blabla wird's Zeit für Code-Beispiele. |
| 166 |
root |
1.1 |
|
| 167 |
|
|
Einen langweiligen Timer realisiert man so. |
| 168 |
|
|
|
| 169 |
|
|
use EV; |
| 170 |
|
|
|
| 171 |
|
|
my $timer = EV::timer 1, 2, sub { |
| 172 |
root |
1.3 |
warn "zeitstempel: " . EV::now; |
| 173 |
root |
1.1 |
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 |
root |
1.2 |
EV::loop kehrt automatisch zurück, wenn es keine aktiven Watcher mehr gibt |
| 182 |
root |
1.1 |
(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 |
root |
1.2 |
Das läuft nur für eine Sekunde. Wichtig ist, daß man das Watcher-Objekt, |
| 191 |
root |
1.1 |
das der Konstruktor liefert, auch aufbewahrt, denn wenn man es vergisst, |
| 192 |
|
|
wird der Watcher automatisch deaktiviert. Hier kehrt C<EV::loop> sofort |
| 193 |
root |
1.2 |
zurück, wenn keine sonstigen Watcher aktiv sind, denn der Timer wird |
| 194 |
|
|
erzeugt, gestartet und sofort wieder gelöscht: |
| 195 |
root |
1.1 |
|
| 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 |
root |
1.2 |
# $_[0] enthält das watcher-objekt |
| 207 |
root |
1.1 |
$_[0]->stop if $line =~ /^q/; |
| 208 |
|
|
}; |
| 209 |
|
|
|
| 210 |
|
|
EV::loop; |
| 211 |
|
|
|
| 212 |
root |
1.3 |
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 |
root |
1.1 |
|
| 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 |
root |
1.2 |
=head2 Spezialitäten |
| 225 |
root |
1.1 |
|
| 226 |
root |
1.3 |
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 |
root |
1.7 |
sollte sich dabei verändern: Wenn auch mtime-Änderungen überwacht werden solle, wird es |
| 254 |
|
|
etwas komplexer, wie in der Manpage beschrieben): |
| 255 |
root |
1.3 |
|
| 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 |
root |
1.13 |
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 |
root |
1.3 |
=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 |
root |
1.8 |
mycb (EV_P_ ev_timer *w, int revents) |
| 321 |
root |
1.3 |
{ |
| 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 |
root |
1.1 |
|
| 335 |
|
|
=head1 Und wie noch? |
| 336 |
|
|
|
| 337 |
root |
1.3 |
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 |
root |
1.9 |
die ineffizienteste Implementation eines Event-Modells ist, die ich je |
| 369 |
|
|
gesehen habe. |
| 370 |
root |
1.3 |
|
| 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 |
root |
1.4 |
=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 |
root |
1.3 |
=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 |
root |
1.11 |
C<Coro>. |
| 420 |
root |
1.4 |
|
| 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 |
root |
1.3 |
|
| 425 |
root |
1.4 |
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 |
root |
1.9 |
man damit ereignisgesteuert (und asynchron) auf das Dateisystem zugreifen |
| 434 |
root |
1.4 |
kann, mit Coro::AIO sogar ähnlich einfach wie mit den eingebauten |
| 435 |
|
|
Perl-Funktionen. |
| 436 |
|
|
|
| 437 |
|
|
=item BDB / Coro::BDB |
| 438 |
root |
1.3 |
|
| 439 |
root |
1.4 |
Was IO::AIO für's Dateisystem ist, ist BDB für die Berkeley DB, nämlich |
| 440 |
root |
1.9 |
ein Modul, mit dem man ereignisgesteuert die Berkeley DB benutzen kann. |
| 441 |
root |
1.3 |
|
| 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 |
root |
1.10 |
In der nächsten (2.2) Release wird es Libev benutzen. Bringt total viel :-> |
| 453 |
root |
1.3 |
|
| 454 |
|
|
http://savannah.gnu.org/projects/gvpe |
| 455 |
|
|
|
| 456 |
|
|
=item Rxvt-Unicode |
| 457 |
|
|
|
| 458 |
|
|
Das allerbeste Terminal überhaupt, vor allem, weil es einen |
| 459 |
root |
1.9 |
Perl-Interpreter embeddet. Und dazu benutzt es (ab Version 8.4 oder so) |
| 460 |
root |
1.3 |
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 |
root |
1.5 |
http://www.deliantra.net/ |
| 474 |
|
|
|
| 475 |
root |
1.3 |
=item OpenMPI |
| 476 |
|
|
|
| 477 |
|
|
Wird, nach eigener Aussage, in der nächsten Release ebenfalls Libev |
| 478 |
|
|
benutzen. Kein embeddetes Perl in Sicht. |
| 479 |
|
|
|
| 480 |
root |
1.5 |
http://www.openmpi.org/ |
| 481 |
|
|
|
| 482 |
root |
1.3 |
=back |
| 483 |
|
|
|
| 484 |
|
|
|
| 485 |
root |
1.2 |
=head1 Hä? |
| 486 |
root |
1.1 |
|
| 487 |
root |
1.3 |
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>. |