ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/cvsroot/docs/pws2009/anyevent.pod
Revision: 1.7
Committed: Sat Jul 18 05:59:11 2009 UTC (17 years, 2 months ago) by root
Branch: MAIN
CVS Tags: HEAD
Changes since 1.6: +1 -1 lines
Log Message:
riddify us of meta.yml garbage in manifest

File Contents

# Content
1 =encoding utf-8
2
3 =head1 AnyEvent - Eine Welt ohne Religion
4
5 In diesem Vortrag möchte ich die neuesten Entwicklungen in Sachen
6 AnyEvent vorstellen (asynchrones IPv4/IPv6, asynchrones DNS, TLS uvm.), sowie
7 einige Hintergrundinformationen zu bestehenden Event-Modulen auf CPAN,
8 sowie Benchmarks, vorstellen.
9
10 Doch zuerst: der Titel klingt sicherlich etwas seltsam - was bedeutet er?
11
12 Nun, AnyEvent ist, wie im Namensteil "Event" steht, ein Event-Modul
13 bzw. eine Event-Bibliothek. Event-Module oder -Bibliotheken stellen
14 im allgemeinen Funktionalität bereit, mit der man auf Ereignisse
15 (Events), warten kann, speziell Ereignisse der Art "Zeitpunkt soundso
16 ist erreicht" und "File Descriptor soundso kann jetzt nichtblockierend
17 gelesen/geschrieben werden."
18
19 Derartige Event-Bibliotheken gibt es zuhauf (Tk, Glib, Event, EV uvm.),
20 doch trotz der offensichtlichen Vorteile Event-basierter Programmierung
21 (z.B. beinahe automatische Parallelisierbarkeit) werden sie kaum in
22 CPAN-Modulen eingesetzt.
23
24 Meiner Meinung nach liegt der Grund schlicht darin, daß alle diese
25 Event-Bibliotheken exklusiv sind: sie dulden niemanden neben sich. Wie
26 bei den meisten Religionen auch, muss man sich einem dieser Modelle
27 ausliefern. Konkret bedeutet dies für Modul-Autoren: benutzt man
28 z.B. Glib in seinem Modul, muss auch jeder Benutzer dieses Modules Glib
29 benutzen, was natürlich eine starke Einschränkung darstellt, vor allem,
30 wenn das Modul selbst eigentlich nur "irgendwelche" Events benötigt, die
31 im Prinzip jede beliebige Event-Bibliothek liefert.
32
33 Einige Module auf CPAN haben versucht, aus dieser Not eine Tugend zu
34 machen: POE z.B. kann andere Event-Module als Implementation benutzen (in
35 der Praxis funktioniert das zwar nur mit einigen wenigen, aber die Idee
36 zählt). Lieder verschlimmert dies das Problem nur: POE z.B. verlangt
37 beinahe religiöse Glaubensbekenntnisse und ist kein bisschen kompatibler,
38 im Gegenteil: obwohl POE Backends für Gtk+ und Event besitzt, kann man
39 POE-Module nicht in einem Gtk+ oder Event-basiertem Programm benutzen:
40 setzt man POE in seinem Modul ein, so muss auch jeder Benutzer des Moduls
41 POE benutzen, sowie auch das Hauptprogramm selbst.
42
43 AnyEvent dagegen ist I<grundsätzlich> anders: Im Stile von anderen
44 C<Any*>-Modulen ist es lediglich eine Schnittstelle zu diesen. Dabei passt
45 es sich an jedes unterstützte Event-Modell an, ohne daß sich die API
46 ändert. Das bedeutet, daß man getrost Module benutzen kann, die AnyEvent
47 benötigen und intern auch benutzen, aber der Benutzer des Moduls sieht
48 davon erstmal nichts und kann jede beliebige Event-Bibliothek benutzen.
49
50 AnyEvent ist 100% Pure-Perl, und kommt mit eigener, schneller,
51 Event-Bibliothek, so daß auch auf Systemen, wo kein anderes Event-Modell
52 verfügbar ist, eventbasiert programmiert werden kann.
53
54 =head2 AnyEvent am Beispiel AnyEvent::CouchDB
55
56 Ein gutes Beispiel dafür ist C<AnyEvent::CouchDB>. Außer im Namen,
57 kommt AnyEvent in der API dieses Moduls nicht vor. Eine einfache
58 Datenbankabfrage sieht dementsprechend auch ganz langweilig aus:
59
60 my $data = $db->view('users/all', { key => 'b' })->recv;
61
62 Obwohl die Abfrage selbst ereignisgesteuert ist, muss man als Benutzer
63 des Moduls kaum darunter leiden, lediglich die Zweiteilung der Aufgabe in
64 "Start-Phase" (C<view>-Methode) und "Resultat-Phase" (C<recv>-Methode) ist
65 typisch. Daß intern AnyEvent werkelt, fällt nicht auf, außer, daß die
66 Abfrage in einem laufenden Tk/Gtk usf.-Programm dieses nicht anhält.
67
68 Im Code werde die Vorteile sichtbar, wenn man mehrere Abfragen "gleichzeitig"
69 (genauer: miteinander verflochten) ausführt:
70
71 my @data = map $_->recv,
72 map $db->view ('users/al', { key => $_ }),
73 qw(key1 key2 key3 key4);
74
75 Auch hierbei muss man nicht darauf achten, welches Event-Modul benutzt
76 wird (oder ob man überhaupt ein spezielles benutzt) - es funktioniert
77 einfach.
78
79 Richtig Spaß macht es, wenn man realisiert, daß man praktisch alle
80 AnyEvent-benutzenden Module beliebig kombinieren kann, und Aufgaben
81 quasi "im Hintergrund" erledigen kann, z.B. mit C<AnyEvent::CouchDB> und
82 C<AnyEvent::HTTP>:
83
84 $db->view('users/all', { key => 'b' })->cb (sub {
85 my $data = shift->revc;
86 # daten erhalten
87 });
88
89 AnyEvent::HTTP::http_get "http://www.porttracker.co.uk", sub {
90 my $html = $_[1];
91 # daten erhalten
92 };
93
94 # hier kann man weitere Dinge erledigen
95
96 Und all das kann man in den eigenen Modulen nutzen, ohne sich irgendwie
97 auf ein bestimmtes Event-Modell festzulegen.
98
99
100 =head2 AnyEvent - Grundlegendes
101
102 AnyEvent selbst wurde letztes Jahr an dieser Stelle ausführlich
103 vorgestellt, daher möchte ich hier nur eine kurze Übersicht
104 bzw. Einführung in AnyEvent als rein Event-Bibliothek geben:
105
106 Wie viele andere Bibliotheken auch, benutzt AnyEvent das Konzept eines
107 "Watchers", eines Objekts, das wie ein Wachhund auf ein bestimmtes
108 Ereignis reagiert (watch/watcher = Wache/Beobachter) und bei Eintreten
109 eine Aktion auslöst, z.B. Aufrufen eines Callbacks.
110
111 Diese Watcher gibt es für die folgenden Ereignistypen:
112
113 =over 4
114
115 =item Zeit - timer
116
117 my $timer = AnyEvent->timer (after => 7, cb => sub {
118 warn "Sieben Sekunden sind abgelaufen!";
119 });
120
121 Timer können nach einer gewissen Zeit ablaufen, oder wiederholt (z.B.
122 alle 3s) Ereignisse auslösen und Callbacks aufrufen.
123
124 =item I/O auf File Handles - io
125
126 my $watcher = AnyEvent->io (fh => *STDIN, poll => 'r', cb => sub {
127 my $line = <STDIN>;
128 # zeile von stdin gelesen
129 });
130
131 I/O-Watcher beobachten einen File Handle und können einen Callback
132 aufrufen, wenn gelesen oder geschrieben werden kann.
133
134 =item Signale - signal
135
136 my $quit = AnyEvent->condvar;
137
138 my $term = AnyEvent->signal (signal => "TERM", cb => sub {
139 $quit->send;
140 });
141
142 ...
143
144 $quit->recv
145
146 Mit Signal-Watchers kann man synchron auf das Auftreten von Signalen
147 warten.
148
149 Das obige Beispiel benutzt eine "condition variable", um mit dem
150 Hauptprogramm zu kommunizieren (mehr Info s.u.).
151
152 =item Kindprozesse sterben sehen - child
153
154 my $w = AnyEvent->child (pid => $pid, cb => sub {
155 warn "pid $pid hat sich beendet\n";
156 });
157
158 Eher selten benötigt, aber sehr schwer zu implementieren (wenn man es
159 richtig tun möchte :), sind Child-Watcher: mit diesen kann man auf das
160 Beenden von ge-fork-ten Prozessen warten.
161
162 =back
163
164 =head3 Wenn man mal nichts tun möchte
165
166 Event-basierte APIs haben eines gemein: Im allgemeinen werden Vorgänge
167 nur gestartet und laufen dann quasi-parallel im Hintergrund ab.
168
169 Aber wenn man nun genügend solche Vorgänge gestartet hat, möchte man ja
170 irgendwann auch mal auf die Ergebnisse warten.
171
172 Dies erledigt entweder das Hauptprogramm, indem es die entsprechenden
173 Funktionen der Event-Bibliothek aufruft (z.B. C<Event::loop> oder C<main
174 Gtk>), oder man benutzt sogenannte "condition variables", mit denen man
175 auf das eintreten eines bestimmten Zustands warten kann.
176
177 "Condition Variables" sind so etwas wie "Rendezvouspunkte" zwischen dem
178 Erzeuger von Daten oder einem Ereignis (z.B. C<AnyEvent::CouchDB->view>
179 oder C<AnyEvent::HTTP::http_get>, aber auch genauso C<< AnyEvent->timer
180 >>) und dem Konsumenten (der Benutzer dieser Funktionen, der die Daten
181 haben oder einfach auf das Ereignis warten möchte).
182
183 =head1 Neues!
184
185 Auf zu neuen Ufern - im letzten Jahr hat sich viel getan, sowohl in
186 AnyEvent selbst, als auch in Sachen "andere Module die AnyEvent benutzen".
187
188 =head2 Altes!
189
190 Die wichtigsten Eigenschaften von AnyEvent sind allerdings beim
191 alten geblieben:
192
193 =over 4
194
195 =item * Die API hat sich kaum verändert, bzw. ist 100%
196 rückwärtskompatibel.
197
198 =item * AnyEvent ist nach wie vor "Pure-Perl".
199
200 =item * Der Event-Teil ist nach wie vor getrennt von den anderen Teilen,
201 das Event-Modul ist klein und wenn man bezahlt nur für das, was man
202 benutzt.
203
204 =back
205
206 Aber nun zu den Neuigkeiten:
207
208
209 =head2 AnyEvent::Strict
210
211 Aus Geschwindigkeitsgründen macht AnyEvent selbst keine
212 Parameterprüfung, ganz einfach deshalb, weil die Prüfung meistens mehr
213 Zeit in Anspruch nimmt als der Rest der Funktion.
214
215 Für einen erfahrenen AnyEvent-Benutzer ist das in der Praxis kein
216 Problem, aber wenn man die API noch nicht genau kennt, können sich so
217 Fehler einschleichen (z.B. alte Event-Hasen benutzen gerne C<fd> statt
218 C<fh> um einen I/O-Watcher zu erzeugen).
219
220 Daher bietet AnyEvent optional eine strenge Prüfung aller
221 Parameter an. Die kann man ganz einfach aktivieren, in dem man die
222 Environment-Variable C<PERL_ANYEVENT_STRICT> auf C<1> setzt, was auf allen
223 meinen Entwicklungsrechnern der Fall ist.
224
225 Falls man diese Prüfung grundsätzlich wünscht (was ich ganz dringend
226 I<nicht> empfehle, siehe aber den Punkt "keine Religion"...), kann man diese
227 auch immer aktivieren:
228
229 use AnyEvent;
230 use AnyEvent::Strict;
231
232 # jetzt wird brutal geprüft.
233
234 Ich gebe zu, das war sicher noch nicht der Brüller, aber sehen wir
235 weiter:
236
237 =head2 AnyEvent::Util
238
239 Dies ist meine Grabbelkiste für nützliche aber eklige Funktionen:
240
241 =over 4
242
243 =item fork_call BLOCK $callback
244
245 Führt den angegebenen BLOCK in einem separaten Prozess aus und ruft
246 danach den $callback mit den Resultatwerten auf. Ist ideal, um lange
247 Berechnungen in einen separaten Prozess zu verlagern:
248
249 fork_call {
250 find_primes_till 1e9
251 } sub {
252 warn "alle primzahen bis 10**9: ", join " ", @_;
253 };
254
255 Die Funktion leaked allerdings unter Windows, aber ich habe bisher noch
256 keinen Weg gefunden, unter einem native-win32-Perl zu forken und das Kind
257 sauber zu beenden (ich glaube, es gibt keinen...).
258
259 =item my $guard = guard BLOCK
260
261 Führt den angegebenen BLOCK aus, wenn C<$guard> zerstört wird. Ist
262 bei ereignisgesteuerter Programmierung total hilfreich, um Sachen
263 aufzuräumen.
264
265 Wenn es vorhanden ist, benutzt AnyEvent das C<Guard>-Modul (ja, das ist
266 Schleichwerbung).
267
268 =item fh_nonblocking $fh, $nonblocking
269
270 Einen File Handle non-blocking zu machen, ist nicht ganz einfach (Windows,
271 Windows, kaputt, kaputt...). C<AnyEvent::Util> erledigt dies mit
272 furchtbaren Hacks unter Windows und elegant überall sonst.
273
274 =back
275
276 Immer noch nicht überzeugt? Ok, dann machen wir mal mit
277 Netzwerkprogrammierung weiter:
278
279
280 =head2 AnyEvent::Socket
281
282 Sockets in Perl haben ein paar gravierende Nachteile: non-blocking
283 connects sind extrem umständlich, IPv6 und IPv4 brauchen völlig
284 inkompatible APIs, DNS blockiert den gesamtem Prozess und liefert darüber
285 hinaus auch nur altmodische IP-Adressen.
286
287 Anders mit AnyEvent::Socket:
288
289 tcp_connect "www.google.com", "80", sub {
290 my ($fh) = @_
291 or die "www.google.com: $!";
292
293 ...
294 };
295
296 Dieser Aufruf löst zuerst C<www.google.com> auf - im Hintergrund, ohne
297 das Programm anzuhalten - und baut dann, ebenfalls im Hintergrund, eine
298 TCP-Verbindung dorthin auf.
299
300 Es versteht sich von selbst, daß Multi-Homed Hosts genauso unterstützt
301 werden wie IPv6, und das ohne zusätzliche XS-Module.
302
303 C<tcp_connect> kann aber noch mehr. Z.b. auf Jabber-Server connecten, was
304 mit Perl alleine fast unmöglich ist, da man mit Perl keine SRV-Records
305 auflösen kann:
306
307 tcp_connect "jabber.org", "xmpp-server=5269", sub {
308 # Die pseudo-XML-Kacke parsed ihr bitte selbst...
309 }, 60; # <- timeout
310
311 Der Name C<tcp_connect> ist leider etwas naiv, tatsächlich werden auch
312 andere Protokolle unterstützt, z.B. local unix Sockets:
313
314 tcp_connect "unix/", "/tmp/.X11-unix/X0", sub { ...
315
316 Listening-Sockets funktionieren prinzipiell genauso einfach, z.B. hier
317 für einen TCPv6-Port:
318
319 tcp_server "::", 80, sub {
320 my ($fh, $host, $port) = @_;
321
322 # jede neue Verbindung führt zu einem Aufruf dieses Callbacks
323 };
324
325 Oder einen beliebigen TCPv4-Port:
326
327 tcp_server "0", undef, sub {
328 my ($fh, $host, $port) = @_;
329 ...
330 }, sub {
331 my ($thishost, $thisport) = @_;
332
333 warn "bound to port $thisport\n";
334 };
335
336 Leider muss man sich selbst darum kümmern, ob IPv6-Sockets auch auf IPv4
337 hören - üblicherweise ja, aber die BSDs haben natürlich mal wieder
338 verbockt und halten sich nicht ans RFC.
339
340 Komplizierteres ist immer möglich - anders als z.B. mit C<IO::Socket> hat
341 man volle Kontrolle über die eigentliche Socket und braucht nicht für
342 jeden etwas spezielleren Wunsch extra Support.
343
344 Und anders als bei anderen Lösungen funktionieren diese Funktionen auch
345 unter Windows korrekt (modulo Tk, daß wie üblich zu kaputt ist, um
346 non-blocking connects stabil zu kriegen, aber AnyEvent arbeitet auch um
347 diese Bugs herum).
348
349 Neben diesen beiden Funktionen gibt es in AnyEvent::Socket eine Unmenge an
350 Utility-Funktionen zum parsen/anzeigen von IP-Adressen, Socket-Adressen
351 und DNS:
352
353 $ipn = parse_ipv4 $dotted_quad
354 $ipn = parse_ipv6 $textual_ipv6_address
355 $ipn = parse_address $text
356 $text = AnyEvent::Socket::aton $ipn
357 ($host, $service) = parse_hostport $string[, $default_service]
358 $sa_family = address_family $ipn
359 $text = format_address $ipn
360 $text = AnyEvent::Socket::ntoa $ipn
361 inet_aton $name_or_address, $cb->(@addresses)
362 $sa = AnyEvent::Socket::pack_sockaddr $service, $host
363 ($service, $host) = AnyEvent::Socket::unpack_sockaddr $sa
364 resolve_sockaddr $node, $service, $proto, $family, $type, $cb->([$family, $type, $proto, $sockaddr], ...)
365
366 Hier verweise ich auf die Dokumentation. Einzig C<parse_hostport>
367 möchte ich genauer erklären: Selbst die Aufgabe, einen Hostnamen und
368 einen Port anzugeben, ist nicht ganz einfach wenn man es richtig machen
369 will. C<parse_hostport> nimmt ein oder zwei Strings und zerlegt diesen in
370 Host und Port, z.B. diese:
371
372 www.linux.org
373 www.x.de:443
374 www.x.de:https=443
375 127.1:22
376 ::1
377 affe::1
378 [10.0.1]:80
379 [www.x.org] 17
380 10.0.0.1 smtp
381
382 Richtig, IPv6 macht das ganze deutlich komplexer. Und IPv6 ist die
383 Zukunft, ob man das nun gut findet oder nicht :/
384
385 Ach ja, Stichwort IPv6 - es kann auch furchtbar nervig sein, wenn
386 Programme grundsätzlich die IPv6-Adresse bevorzugen, die gerade nicht
387 erreichbar ist. Der Standard bei AnyEvent ist zur Zeit IPv4 den
388 Vorzug zu geben, was sich allerdings über die Environment-Variable
389 C<PERL_ANYEVENT_PROTOCOLS> beeinflussen lässt.
390
391
392 =head2 AnyEvent::DNS
393
394 Nur am Rande möchte ich AnyEvent::DNS erwähnen. Ursprünglich war es nur
395 dazu gedacht, die Adressen für C<AnyEvent::Socket> zu resolven. Das Modul
396 ist aber ein kompletter Stub-Resolver, der beliebige DNS-Record-Typen,
397 EDNS0, IPv6 und virtual circuit mode supported.
398
399 Das Modul ist in der Praxis ca. halb so schnell wie z.b. EV::ADNS (braucht
400 natürlich viel mehr Speicher, blockiert aber im Gegensatz zu EV::ADNS
401 nie).
402
403 Es gibt Hilfsunktionen (hier nur eine Auswahl):
404
405 AnyEvent::DNS::a $domain, $cb->(@addrs)
406 AnyEvent::DNS::mx $domain, $cb->(@hostnames)
407 AnyEvent::DNS::srv $service, $proto, $domain, $cb->(@srv_rr)
408 AnyEvent::DNS::ptr $domain, $cb->(@hostnames)
409 AnyEvent::DNS::reverse_lookup $ipv4_or_6, $cb->(@hostnames)
410 AnyEvent::DNS::reverse_verify $ipv4_or_6, $cb->(@hostnames)
411
412 Und eine Resolver-Klasse:
413
414 use Data::Dumper;
415 use AnyEvent::DNS;
416 AnyEvent::DNS::resolver->resolve (
417 "google.com", "*", my $cv = AnyEvent->condvar);
418 warn Dumper [$cv->recv];
419
420 # gekürztes Ergebnis:
421 # [
422 # [ 'google.com', 'soa', 'in', 'ns1.google.com', 'dns-admin.google.com',
423 # 2008052701, 7200, 1800, 1209600, 300 ],
424 # [
425 # 'google.com', 'txt', 'in',
426 # 'v=spf1 include:_netblocks.google.com ~all'
427 # ],
428 # [ 'google.com', 'a', 'in', '64.233.187.99' ],
429 # [ 'google.com', 'mx', 'in', 10, 'smtp2.google.com' ],
430 # [ 'google.com', 'ns', 'in', 'ns2.google.com' ],
431 # ]
432
433
434 =head2 AnyEvent::Handle
435
436 Nun zum ehrgeizigsten Teil der Neuerungen: C<AnyEvent::Handle>.
437
438 Die Probleme, die dieses Modul lösen möchte, kommen in der Praxis
439 häufig vor: Formatted-I/O, Pipelining und TLS-Verschlüsselung.
440
441 Früher habe ich immer ad-hoc Lösungen für diese Probleme implementiert,
442 da mir schlicht die Erfahrung gefehlt hat, wie man alle diese Features in
443 ein allgemeines Perl-Modul "gießt".
444
445 C<AnyEvent::Handle> versucht diese Lösung zu
446 sein: AnyEvent::Handle-Objekte sind Wrapper um existierende File
447 Handles. Im folgenden beschreibe ich die Lösung, die AnyEvent::Handle
448 für die oben beschriebenen Probleme bietet:
449
450 =over 4
451
452 =item Formatted I/O
453
454 Um auf ein AnyEvent::Handle-Objekt zu schreiben, benutzt man
455 C<push_write>. Das C<push> deutet darauf hin, daß es einen Puffer für
456 die Daten gibt, und C<push_write> hängt die Daten einfach an diesen an:
457
458 $hdl->push_write ("GET / HTTP/1.0\015\012\015\012");
459
460 Mit mehr als einem Argument fordert man zusätzliche Formatierungen an,
461 die meisten dieser Formatierungen gibt es sowohl für die Schreib- als
462 auch die Leseseite:
463
464 $hdl->push_write (netstring => "xyz"); # djb netsrings
465 $hdl->push_write (packstring => "w", "data"); # benutzt pack()
466 $hdl->push_write (json => [1, 2, 3, 4]); # benutzt JSON
467 $hdl->push_write (storable => $ref); # benutzt Storable
468
469 Schreiben ist einfach, Lesen ist schwieriger. Anders als beim Schreiben
470 enthält der Puffer keine Daten, sondern die Callbacks, die der Reihe nach
471 aufgerufen werden, wenn Daten eintreffen.
472
473 Die Flexibilität entsteht dadurch, daß man Callbacks ans Ende des Puffers anhängen kann:
474
475 $hdl->push_read (json => sub { my $data = $_[1] });
476
477 Aber auch vor dem Anfang einschieben kann:
478
479 $hdl->unshift_read (json => sub { my $data = $_[1] });
480
481 Interessant ist dies vor allem, weil man hierdurch recht einfach auch
482 komplexe Protokolle mit Pipelining implementieren kann.
483
484 Man kann jederzeit eigene Formatierungstypen global für alle Handles
485 hinzufügen. Zusätzlich zu den schon vorgestellten Typen für die
486 Schreibrichtung, die auch für die Leserichtung existieren, gibt es noch:
487
488 $hdl->push_read (line => $eol, $cb); # zeilen
489 $hdl->push_Read (regex => $accept[, $reject[, $skip], $cb);
490
491 =item Pipelining
492
493 Pipelining bedeutet, daß man auf einer bestehenden Verbindung mehrere
494 Anfragen gleichzeitig losschickt. Die Herausforderung liegt darin, daß
495 man beim Empfang der Antworten flexibel auf Ausnahmen reagieren können
496 muss.
497
498 Bei HTTP beispielsweise weiß man erst nach Parsen des Headers, wie lang
499 der Body wird.
500
501 AnyEvent::Handle erledigt dies mit einer Kombination aus C<push_read> und
502 C<unshift_read>:
503
504 # sende requests
505 for (@urls) {
506 $hdl->push_write ("GET $_ HTTP/1.0\015\012\015\012");
507 }
508
509 # parse antworten
510 for (@urls) {
511 # lese header
512 $hdl->push_read (line => "\015\012\015\012", sub {
513 my ($hdl, $header) = @_;
514
515 my $content_length = extract "Content-Length", $header;
516
517 $hdl->unshift_read (chunk => $content_length, sub {
518 my ($hdl, $body) = @_;
519
520 # fertig
521 });
522 });
523 }
524
525 Der springende Punkt ist, daß C<unshift_read> erst I<nach> dem Empfang
526 des Headers ausgeführt wird. Dadurch kann man z.B. verschiedene Arten von
527 Antworten parsen, oder auf unerwartete Fehler reagieren, obwohl vielleicht
528 schon Antworten auf die nächsten Requests empfangen wurden.
529
530 =item TLS/SSL
531
532 TLS ist der Horror. Nicht nur, aber vor allem auch wegen der grauenvollen
533 OpenSSL-API (GnuTLS ist geringfügig besser, doch sucht man vergebens nach
534 einem guten Perl-Modul dafür). Der Beweis dafür ist, daß es praktisch
535 kein Modul gibt, daß non-blocking TLS connects korrekt und wirklich
536 non-blocking durchführt.
537
538 Es hilft auch nicht gerade, daß Net::SSLeay nur einen Bruchteil der
539 OpenSSL-API umsetzt.
540
541 AnyEvent::Handle (to boldly go...) versucht einen ganz neuen Ansatz für
542 diese Problematik, bei der OpenSSL vom eigentlichen File Handle komplett
543 getrennt wird, d.h. gar keinen Zugriff auf diesen hat. Dadurch wird
544 garantiert, daß OpenSSL auf gar keinen Fall blockieren kann.
545
546 Ganz wie der Rest von AnyEvent ist einfach einfach: wenn man zu einem
547 TLS-Server connecten möchte, setzt man C<tls> auf C<"connect">, als
548 TLS-Server dagegen setzt man es auf C<"accept">.
549
550 Hat man kompliziertere Ansprüche, wie Zertifikate oder
551 Verification-Callbacks, so kann man sein eigenes Net::SSLeay::CTX-Objekt
552 oder das Net::SSLeay-Objekt für die Verbindung selbst übergeben.
553
554 Selbstverständlich kann man den TLS-Handshake zu einem beliebigen
555 Zeitpunkt beginnen, nicht nur am Anfang der Verbindung.
556
557 =back
558
559 Mit AnyEvent::Handle wird manches erstaunlich einfach. Hier ist z.B. ein
560 (ganz primitiver) HTTPS-Client (übrigens das komplette Programm):
561
562 use AnyEvent;
563 use AnyEvent::Socket;
564 use AnyEvent::Handle;
565
566 my $cv = AnyEvent->condvar;
567
568 tcp_connect "www.google.com", "443", sub {
569 my ($fh) = @_ or die;
570
571 my $hdl; $hdl = new AnyEvent::Handle
572 fh => $fh,
573 timeout => 60,
574 tls => "connect",
575 on_eof => sub {
576 undef $hdl; # gibt handle frei
577 $cv->send; # isch hab' ferdisch
578 },
579 on_read => sub {
580 my ($hdl) = @_;
581 print $hdl->{rbuf};
582 $hdl->{rbuf} = "";
583 };
584
585 $hdl->push_write ("GET / HTTP/1.0\015\012\015\012");
586 };
587
588 $cv->recv;
589
590 Zuerst zum Einsatz kommt C<tcp_connect>, um den non-blocking Connect
591 durchzuführen. Danach wird das Handle-Objekt erzeugt, konfiguriert,
592 und danach lediglich der Request gesendet, der Rest des Protokolls wird
593 ereignisgesteuert abgehandelt. Der Unterschied zwischen TLS (https) und
594 nicht-TLS (http) besteht lediglich in dem Parameter C<tls => "connect">,
595 der einen sofortigen TLS-Client-Handshake auslöst (will man in der
596 Mitte der Verbindung switchen, z.b. für SMTP, kann man jederzeit die
597 C<starttls>-Methode aufrufen).
598
599 Darüber hinaus gibt es eine Menge Parameter, mit dem man Verhalten,
600 Fehlerbehandlung, Ressourcenbenutzung auf seine Anforderungen abstimmen
601 kann. Für ganz spezielle Anwendungen kann man von AnyEvent::Handle auch
602 eigene Klassen ableiten, aber in den meisten Fällen ist dies unnötig.
603
604 Ein Nachteil von AnyEvent::Handle ist allerdings, daß die Abstraktion
605 selbst nicht kostenlos ist: Methodenaufrufe in Perl sind vergleichsweise
606 langsam, und AnyEvent::Handle benutzt sehr viele davon. In den meisten
607 Fällen merkt man davon allerdings nichts, da der Overhead durch
608 AnyEvent::Handle immer noch sehr gering ist, wenn man mit den Daten auch
609 noch etwas tun möchte.
610
611 =back
612
613
614 =head2 Benchmarks
615
616 Ich bin es gewohnt, meine eigene Lösungen zu schreiben, notfalls immer
617 und immer wieder. Bevor ich eine (hilfreiche) Abstraktion ruhigen
618 Gewissens benutzen kann, muss ich immer erst wissen, wie viel sie kostet,
619 damit ich eine vernünftige Abwägung machen kann.
620
621 Deshalb habe ich drei Benchmarks durchgeführt, um herauszufinden, wie
622 hoch der Overhead von AnyEvent gegenüber der direkten Benutzung von
623 Event-Bibliotheken ist, und wie verschiedene Event-Bibliotheken bei
624 typischen Server-Situationen skalieren, sowohl für Server mit sehr vielen
625 Verbindungen, als auch für Server mit sehr wenigen.
626
627 =head3 Benchmark 1: Overhead
628
629 Um den Overhead von AnyEvent selbst zu testen, erzeugt dieser Benchmark
630 sehr viele Timer (mit einem Time-out von 0 Sekunden) und ebensoviele
631 I/O watcher auf STDOUT (üblicherweise eine tty), der auf den
632 "schreibbar"-Zustand wartet.
633
634 Dann lässt er alle Watcher genau einmal ihren Callback aufrufen und
635 zerstört die Watcher dann.
636
637 Gemessen wird die Zeit, die es jeweils braucht, einen Watcher zu erzeugen,
638 den Callback auszuführen und den Watcher wieder zu zerstören.
639
640 Die Kernel-Schnittstelle sollte einen relativ geringen Einfluss besitzen,
641 sofern die Event-Bibliothek einigermaßen effizient implementiert wurde,
642 da nur ein einziges mal ein einziger File-Descriptor abgefragt werden
643 muss.
644
645 (Der Benchmark liegt AnyEvent als F<eg/bench> bei).
646
647 Die Spalten in der Tabelle haben folgende Bedeutung:
648
649 I<Watcher> ist die Anzahl der erzeugten Watcher-Objekte, d.h. die Anzahl
650 der Timer + I/O-Watcher.
651
652 I<Bytes> ist die Anzahl der RAM-Bytes, die ein Watcher-Objekt im Schnitt
653 verbraucht. Dabei wird der Perl- und C-Anteil gezählt.
654
655 I<Create> ist die durchschnittliche Zeit für die Erzeugung eines Watchers
656 in millionstel Sekunden.
657
658 I<Invoke> ist die Zeit, in millionstel Sekunden, die die Ausführung des
659 Callbacks dauerte. Der Callback selbst zählt lediglich eine Variable
660 herunter.
661
662 I<Destroy> schließlich ist die durchschnittliche Zeit für das freigeben
663 eines Watcher-Objektes, in millionstel Sekunden.
664
665 Alle Benchmarks wurden auf einem Core2-Quad/3.6GHz durchgeführt, wobei
666 das Programm mit Echtzeitpriorität auf CPU #3 lief.
667
668 Name Watcher Bytes Create Invoke Destroy Hinweise
669 /uSec /uSec
670 EV/EV 400000 224 0.47 0.35 0.27 EV direkt
671 EV/Any 100000 224 2.88 0.34 0.27 EV über AnyEvent
672 Perl/Any 100000 452 4.13 0.73 0.95 AnyEvent/pure perl
673 Event/Event 16000 517 32.20 31.80 0.81 Event direkt
674 Event/Any 16000 590 35.85 31.55 1.06 Event über AnyEvent
675 Glib/Any 16000 1357 102.33 12.31 51.00 >quadratisches Wachstum
676 Tk/Any 2000 1860 27.20 66.31 14.00 SEGV bei >> 2000 watchers
677 POE/Event 2000 6328 109.99 751.67 14.02 via POE::Loop::Event
678 POE/Select 2000 6027 94.54 809.13 579.80 via POE::Loop::Select
679
680 Wie erwähnt, ist der Benchmark so designed, daß das Kernel-Interface
681 (select, epoll etc.) keinen Einfluss hat. Das bedeutet, daß die
682 Skalierbarkeit der Event-Bibliothek hier I<nicht> gemessen wird.
683
684 Die Anzahl der Watcher wurde so gewählt, daß die Ausführungszeit für
685 jede Event-Bibliothek ähnlich war: würde man mit EV weniger Watcher
686 wählen, bekäme man keine aussagekräftigen Zahlen, würde man mit Tk
687 mehr wählen, würde es crashen, und würde man bei Glib oder POE mehr
688 wählen, würde ich wohl noch nächstes Jahr auf die Ergebnisse
689 warten.
690
691 Wie man sieht, ist die Ausführung von Callbacks und das Zerstören von Watchern
692 bei EV direkt (ohne AnyEvent) und bei AnyEvent mit EV als backend identisch, was daran liegt, daß AnyEvent keinerlei Overhead hinzufügt.
693
694 Lediglich beim Erzeugen von Watchern ist AnyEvent+EV deutlich langsamer
695 als EV direkt. Das liegt daran, daß AnyEvent a) einen Methodenaufruf und
696 b) benannte Parameter benutzt. Diese beiden Umstände machen das Erzeugen
697 von Watchern mehr als fünf mal langsamer als die direkte Benutzung von
698 EV.
699
700 Auch ist der Speicherverbrauch mit durchschnittlich 224 Bytes bei beiden
701 gleich.
702
703 Sehr erfreulich ist auch, daß die Pure-Perl Event-Implementation nicht
704 viel hinterherhinkt: Erzeugen von Watchern und die Callback-Aufrufe
705 sind ungefähr halb so schnell wie mit der stark optimierten libev
706 C-Bibliothek. Der Speicherverbrauch ist ebenfalls noch im Rahmen und liegt
707 ca. beim doppelten dessen von EV.
708
709 Etwas enttäuscht hat mich Event: Event war meine Bibliothek der Wahl, ich
710 hielt sie für sehr schnell und korrekt, musste aber im letzten Jahrzehnt
711 einige größere Design-Schwächen erkennen.
712
713 Überrascht hat mich allerdings, wie viel langsamer Event gegenüber einer
714 Pure-Perl Implementation ist. Tatsächlich habe ich einige Zeit mit dem
715 Quellcode von Event verbracht und musste feststellen,daß Event in der Tat
716 gewaltigen Aufwand beim Aufruf von Callbacks betreibt, was sich in der
717 Zeit niederschlägt. Die langsame Erzeugungszeit liegt dagegen schlicht
718 daran, daß jeder Parameter intern in einen dynamischen Methodenaufruf
719 umgesetzt wird.
720
721 Wie man am Speicherverbrauch und dem Zeitunterschied sieht, ist die
722 direkte Benutzung von Event etwas effizienter als den Umweg über AnyEvent
723 zu gehen, allerdings ist der Overhead im Vergleich zur Langsamkeit von
724 Event sehr gering.
725
726 Wie man an den anderen Zeilen sieht, liegt Event allerdings recht
727 gut: Glib ruft Callbacks zwar schneller auf, die anderen Zeiten sind aber grauenhaft.
728
729 Auch Tk (sofern es nicht crasht :) ist nicht wirklich schneller, und POE
730 ist jenseits von Gut und Böse.
731
732 Tatsächlich ist die Implementation von AnyEvent auf POE nicht sehr
733 effizient, da POE dies ausschließt. Wie der nächste Benchmark beweist,
734 ist POE allerdings unter realistischen Bedingungen genauso langsam.
735
736 Eine anderen Sicht der obigen Resultate ist, daß die Behandlung
737 eines Ereignisses mit EV ca. 1_600 Taktzyklen, mit AnyEvents Pure Perl
738 Implementation ca. 3_100 Zyklen und mit POE beinahe 3_000_000 Taktzyklen
739 benötigt_.
740
741 =head3 Benchmark 2: ein großer Server
742
743 Was den AnyEvent-Overhead angeht, reicht mir der obige Benchmark völlig,
744 um mich zu beruhigen: der Overhead von AnyEvent über die Event-Bilbiothek
745 hinaus ist gering, wenn man von EV absieht (was natürlich daran liegt,
746 daß EV so schnell ist).
747
748 Um die Pure-Perl Event-Bibliothek von AnyEvent zu testen, muss aber
749 ein anderer Benchmark her. Außerdem wollte ich unbedingt wissen, wie
750 verschiedene Systeme in der Praxis abschneiden.
751
752 Um einen großen Server zu simulieren, gibt es ein paar
753 Standardbenchmarks. Einer davon ist es, sehr sehr viele Socketpaare zu
754 erzeugen. Auf der einen Seite jedes Paares ist ein "Server", der ein
755 einzelnes Octet liest, und dieses dann auf eine zufällige andere Socket
756 schreibt. Jedes Socketpaar hat einen assoziierten Timer, der bei jeder
757 Aktivität zurückgesetzt wird.
758
759 Auf diese Weise wandern die Octets auf einem Teil der Verbindungen hin und
760 her, was in etwa einem realen Server entspricht: sehr viele Verbindungen,
761 aber nur ein kleiner Teil davon ist in jeder Iteration aktiv.
762
763 Im folgenden werden 10_000 Socketpaare (d.h. 20_000 Sockets) erzeugt, und
764 davon sind jeweils 100 "aktiv".
765
766 (Der Benchmark liegt AnyEvent als F<eg/bench2> bei).
767
768 Die Spalten bedeuten im einzelnen:
769
770 I<Create> ist die Zeit, die es braucht, um ein Socketpaar zu erzeugen und
771 alle Watcher zu registrieren, wieder in millionstel Sekunden.
772
773 I<Request> ist bei weitem die wichtigste Größe. Sie gibt an, wie lange
774 es im Schnitt dauert, um eine "Anfrage" zu bearbeiten und den Timeout
775 zurückzusetzen.
776
777 Name Create Request
778 /uSec /uSec
779 EV 69.01 11.16
780 Perl 73.32 35.87
781 Event 212.62 257.32
782 Glib 651.16 1896.30
783 POE 349.67 12317.24 mit POE::Loop::Event
784
785 Dieser Benchmark misst nun direkt die Skalierbarkeit und die
786 Geschwindigkeit der Event-Bibliothek.
787
788 EV hat hier einen großen Vorteil, da es epoll, einen weitaus
789 effizienteren Mechanismus als select oder poll, benutzen kann, während
790 alle anderen entweder select oder poll benutzen.
791
792 Wenig verwunderlich ist EV hier wieder mit Abstand am schnellsten.
793
794 Sehr erstaunt war ich über das sehr gute Abschneiden der Pure-Perl
795 Implementation. Sie ließ die anderen C-Bibliotheken weit hinter
796 sich. Möglicherweise liegt der Grund hierfür darin, daß AnyEvent
797 ganz ähnliche Algorithmen wie EV benutzt um I/O-Watcher und Timer zu
798 verwalten, und ansonsten sehr abgespeckt ist.
799
800 Event leidet sicher daran, daß es so teuer ist, Watcher zu erzeugen und
801 upzudaten.
802
803 Woran Glib leidet, ist schlichtweg unglaubliche Ineffizienz: Alle
804 Watcher werden bei jeder Iteration vielmals angeschaut, teilweise
805 sogar verglichen. Ich glaube nicht, daß man eine derart ineffiziente
806 Event-Bibliothek erhielte, wenn man sich hinsetzte und einfach drauf los
807 schriebe ohne sich Gedanken zu machen. Tatsächlich ist Glib auch nicht
808 dafür gedacht, effizient zu sein oder mehr als einen File Descriptor zu
809 unterstützen (den zum X-Server nämlich).
810
811 POE ist sicherlich etwas langsamer, als es sein könnte, da für jede
812 Verbindung drei "sessions" eingesetzt wurden, während POE eine Session
813 pro "Verbindung" vorschlägt. Allerdings ist derlei Kritik am Benchmark
814 irrelevant: Auch in einem echten Server würde man für jede Session eine
815 Session benutzen, und selbst wenn POE dreimal schneller würde wäre es
816 immer noch über 100 mal langsamer als die Pure-Perl Event-Implementation
817 von AnyEvent.
818
819 Im übrigen wurde in diesem Benchmark sogar die Pure-Perl Version von POE durch
820 eine optimierte Variante ersetzt wurde, die das C<Event>-Modul benutzt.
821
822 =head3 Benchmark 3: ein klitzekleiner Server
823
824 Benchmarks für riesige Systeme sind sicher wichtig, aber wenn man "nur
825 eben" mal AnyEvent benutzt, sollte es auch schnell sein, wenn man nur
826 sehr wenige aktive Verbindungen hat.
827
828 Im folgenden wurde daher nur acht Socketpaare benutzt, von denen jeweils drei aktiv sind:
829
830 Name Create Request
831 /uSec /uSec
832 EV 20.00 6.54
833 Perl 25.75 12.62
834 Event 81.27 35.86
835 Glib 32.63 15.48
836 POE 261.87 276.28 mit POE::Loop::Event
837
838 Wie man sieht, ändert sich nichts drastisch: Glib ist nun so schnell
839 wie die anderen, aber EV und AnyEvents Pure-Perl Implementation sind
840 trotzdem schneller.
841
842 Während POE weiterhin stark hinterherhinkt, für drei Verbindungen aber
843 absolut adäquat ist :->
844
845
846 =head2 Ausblick auf CPAN
847
848 AnyEvent existiert nicht in Isolation: Es gibt inzwischen eine stattliche
849 Anzahl von CPAN-Modulen die AnyEvent und nur AnyEvent als Abhängigkeit
850 besitzen. Für AnyEvent ist es nicht so wichtig wie für andere
851 "Frameworks" (wie POE), viele weitere CPAN-Module zu benutzen, da
852 AnyEvent-Module ja mit anderen Frameworks kombiniert werden können,
853 umgekehrt ist dies allerdings nicht der Fall (AnyEvent + POE Programm
854 geht, POE + Tk-Programm geht nicht).
855
856 Hier ist eine fast erschöpfende Auswahl von AnyEvent-Modulen auf CPAN:
857
858 =over 4
859
860 =item AnyEvent::HTTP
861
862 Ein ganz einfacher HTTP-Client. Da man mit LWP keine parallelen Abfragen
863 durchführen im selben Prozess kann, ist es recht hilfreich :)
864
865 =item AnyEvent::AIO
866
867 Integriert IO::AIO transparent in AnyEvent. AnyEvent::AIO ist ein ideales
868 Pendant zu AnyEvent: AnyEvent abstrahiert non-blocking I/O, IO::AIO
869 abstrahiert asynchrones I/O.
870
871 =item AnyEvent::DBI
872
873 Langsames, aber asynchrones, DBI-Frontend.
874
875 =item AnyEvent::CouchDB
876
877 Eine Schnittstelle zur CouchDB. Ein must have!
878
879 =item AnyEvent::BDB
880
881 Asynchrone Schnittstelle zur guten alten BerkelyDB.
882
883 =item AnyEvent::IRC
884
885 Event basiertes IRC.
886
887 =item AnyEvent::XMPP
888
889 Alternative zum eigenen Parser für Jabber-Pseudo-XML.
890
891 =item AnyEvent::FastPing
892
893 Wenn man mal eine Million Ping-Pakete pro Sekunde verschicken will. Eignet
894 sich ideal um Firewalls abzuschießen :)
895
896 =item AnyEvent::Mojo
897
898 Wenn ich's bloß wüsste...
899
900 =item AnyEvent::HTTPD
901
902 Ein einfacher Webserver zum Einbetten in die eigene Applikation.
903
904 =item Coro::AnyEvent
905
906 Die Kombination von Coro-Threads und AnyEvent ist ideal - komplexe Logik
907 kann man bequem per Thread implementieren, Low-Level Event-Handling geht
908 meist per AnyEvent angenehmer.
909
910 =back