ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/cvsroot/docs/io-aio.pod
Revision: 1.2
Committed: Thu Feb 1 16:24:36 2007 UTC (19 years, 7 months ago) by root
Branch: MAIN
CVS Tags: HEAD
Changes since 1.1: +0 -0 lines
State: FILE REMOVED
Log Message:
*** empty log message ***

File Contents

# User Rev Content
1 root 1.1 =encoding utf-8
2    
3     =head1 IO::AIO - Asynchronous Input/Output
4    
5     =head2 Motivation
6    
7     In vielen Situationen wäre es schön (oder ist man sogar gezwungen),
8     bestimmte Reaktionszeiten einzuhalten: Ein Web-Server, der viele Sockets
9     bedient, sollte sich möglichst rechtzeitig um diese kümmern können. Ein
10     interktives Spiel muss bestimmte Antwortzeiten einhalten. Und manchmal
11     wäre es einfach nur hilfreich, wenn man etwas anderes tun könnte,
12     während der Rechner auf die Festplatte wartet.
13    
14     Unix bietet herkömmlicherweise relativ wenig Unterstützung für
15     derartige Anliegen. Daher habe ich das Modul IO::AIO entwickelt, mit dem
16     sich alle wichtigen I/O-Operationen asynchron abwickeln lassen.
17    
18     =head2 Asynchron mit Synchronisation
19    
20     Asynchron bedeutet, daß die eigentliche Ein-/Ausgabe, z.B. das schreiben
21     einer Datei, gleichzeitig mit anderen Aktivitäten eines Programmes
22     geschieht. Dies unterscheidet asynchrone I/O von non-blocking I/O,
23     bei letzterem wird das Programm zwar ebenfalls nicht behindert, die
24     eigentliche Ein-/Ausgabe findte jedoch immer noch synchron statt.
25    
26     Beispiel:
27    
28     aio_readdir "/etc", sub {
29     my $entries = shift
30     or die "error while reading /etc: $!";
31     print "read /etc, entries: @$entries\n";
32     };
33    
34     Dieser Aufruf erzeugt eine readdir-Anfrage, die asynchron bearbeitet
35     wird, d.h. C<aio_readdir> kehrt sofort zurück. Sobald das Verzeichnis
36     eingelesen wurde, wird der übergebene Callback mit den Einträgen
37     aufgerufen.
38    
39     Da Perl nicht einfach jederzeit unterbrochen werden kann (bzw. man dies
40     auch garnicht zu jedem Zeitpunkt möchte), geschieht die Verarbeitung
41     von Resultaten in IO::AIO synchron, d.h. die eigentliche Ein-/Ausgabe
42     findet asynchron statt, aber der Callback, der das Ende der Operation
43     signalisiert, wird nur zu bestimmten Zeiten aufgerufen, und zwar immer
44     dann, wenn das Perl-Programm IO::AIO::poll_cb aufruft.
45    
46     Wie man dies tut ist relativ unwichtig. Wann dagegen ist wichtig, und um
47     die Integration von IO::AIO in bestehende Event-Modelle zu erleichtern,
48     stellt IO::AIO einen filedeskriptor zur Verfügung: sobald dieser lesbar
49     wird, sollte man C<poll_cb> aufrufen. Für Gtk2 sieht das z.B. so aus:
50    
51     add_watch Glib::IO IO::AIO::poll_fileno,
52     in => sub { IO::AIO::poll_cb; 1 };
53    
54     Für AnyEvent dagegen etwas komplexer, da es einen Filehandle benötigt:
55    
56     open my $fh, "<&=" . IO::AIO::poll_fileno or die "$!";
57     my $w = AnyEvent->io (fh => $fh, poll => ’r’, cb => sub { IO::AIO::poll_cb });
58    
59     =head2 The Works
60    
61     Hat man IO::AIO erst einmal integriert, kann man wild drauf loslegen. Fast
62     alle Operationen, die mit Dateien zu tun haben, werden von IO::AIO
63     unterstützt:
64    
65     aio_sendfile aio_read aio_write aio_open aio_close aio_stat
66     aio_lstat aio_unlink aio_rmdir aio_readdir aio_symlink
67     aio_readlink aio_fsync aio_fdatasync aio_rename aio_link
68     aio_mknod aio_mkdir
69    
70     Allen ist gemeinsam, daß sie ein oder mehrere Parameter verlangen und als
71     letztes einen Callback, der im Fehlerfall oder bei erfolgreichem Abschluß
72     der Operation aufgerufen wird. Anders als die eingebauten Perl-Funktionen
73     geben die meiste aio-Operationen direkt den Status des entsprechenden
74     Syscalls zurück:
75    
76     # Perl
77     stat $path or die ...
78    
79     # IO::AIO
80     aio_stat $path, # vvv and statt or
81     sub { $_[0] and die "..." }
82    
83     =head2 The Features
84    
85     IO::AIO bietet auch eine Reihe von zusammengesetzten Anfragen.
86    
87     So verschieben bzw. kopieren C<aio_move> C<aio_copy> einzelne Dateien. Mit
88     C<aio_load> kann man eine Datei komplett einlesen, C<aio_rmtree>
89     löscht Verzeichnisbäume, C<aio_readahead> liest eine Datei in den
90     OS-Cache (pre-caching) und C<aio_scandir> liefert alle Einträge eines
91     Verzeichnisses in zwei Gruppen sortiert zurück: Verzeichnisse und
92     Sonstige. Der Algorithmus von C<aio_scandir> ist recht komplex aber dafür
93     sehr, sehr schnell.
94    
95     =head2 The Specialties
96    
97     Die meisten der etwas spezielleren Anfragen (sogenannte I<composite
98     requests>) bestehen aus mehreren Einzelanfragen. C<aio_load> z.B. öffnet
99     die Datei und liest dann deren Inhalt mit C<aio_read>. Damit diese
100     Anfragen nach aussen wie eine Anfrage aussehen, kann man Anfragen mit
101     C<aio_group> zusammengruppieren.
102    
103     Die Implementation von C<aio_load> sieht Beispielsweise so aus:
104    
105     sub aio_load($$;$) {
106     aio_block {
107     my ($path, undef, $cb) = @_;
108     my $data = \$_[1];
109    
110     my $pri = aioreq_pri;
111     my $grp = aio_group $cb;
112    
113     aioreq_pri $pri;
114     add $grp aio_open $path, O_RDONLY, 0, sub {
115     my $fh = shift
116     or return $grp->result (-1);
117    
118     aioreq_pri $pri;
119     add $grp aio_read $fh, 0, (-s $fh), $$data, 0, sub {
120     $grp->result ($_[0]);
121     };
122     };
123    
124     $grp
125     }
126     }
127    
128     Zur Erläuterung: C<aio_block> ist eine Art Locking-Mechanismus, der
129     benötigt wird, wenn man asynchone Rückmeldungen wünscht. Das ist nicht
130     Normalbetrieb und darf hier ignoriert werden.
131    
132     Zuest wird daher eine Gruppe erzeugt (C<aioreq_pri> dient dazu,
133     Anfragen untereinander zu prioritisieren). In diese Gruppe wird eine
134     C<aio_open>-Anfrage gesteckt und - falls erfolgreich - gleich noch das
135     C<aio_read>.
136    
137     =head2 Request-Objekte
138    
139     Alle Anfragen liefern (auf Wunsch :) ein Objekt zurück:
140    
141     my $buffer;
142     my $loader = aio_load $path, $buffer, sub {
143     # $buffer voll, hoffentlich
144     };
145    
146     Mit diesem Objekt kann man jede Operation unter andere, abbrechen, falls
147     diese nicht schon bearbeitet wird:
148    
149     $loader->cancel; # wills nicht mehr haben
150    
151     Dies ist vor allem für interaktive Programme nützlich, die auf
152     Benutzerwunsch eine Operationen starten, diese aber abbrechen, falls der
153     Benutzer nicht mehr daran interessiert ist.
154    
155     =head2 Anwendungsbeispiel
156    
157     IO::AIO wird, unter anderem, von dne folgendne drei Programmen benutzt:
158    
159     =head3 Gtk2::CV
160    
161     Ein interaktives Bildbetrachtungsprogramm. Geschrieben wurde es, um die
162     wichtigsten Features von XV in das 21te Jahrhundert zu retten, bzw.
163     schnell und effizient große Bildverzeichnisse zu durchforsten. Es benutzt
164     IO::AIO extensiv, um z.B. Dateien für den Thumbnailprozess zu lesen (es
165     ist wahrscheinlich einer der schnellsten indexer "wo gibt"), Dateien zu
166     verschieben, zu löschen und vieles mehr.
167    
168     =head3 myhttpd
169    
170     Ist ein single-Prozess-Webserver, der schon vor fast 10 Jahren 1400
171     Downloader gleichzeitig mit 80MBit/s von nur zwei Festplatten bedienen
172     konnte. Damals noch mit Linux::AIO, benutzt er inzwischen IO::AIO für
173     fats alle Dateiperationen, insbesondere natürlich für das Serven großer
174     Dateien.
175    
176     =head3 Crossfire+
177    
178     Crossfire+ ist ein grafisches Multiplayer-Online-RPG (bzw. eines der
179     ältesten). Perl und IO::AIO haben ihm vor kurzer Zeit beigebracht,
180     Karten/Levels und andere Spieldaten im Hintergrund zu Laden und zu
181     Speichern, so daß auch bei vielen Spielern und einem laufenden Backup im
182     Hintergrund keine lästigen Pausen mehr entstehen.
183    
184     =head2 Coro::AIO - IO::AIO linearisiert
185    
186     Mit Coro::AIO kann man alle IO::AIO-Operationen wieder "linear"
187     benutzen. Crossfire+ z.B. benutzt IO::AIO meistens nicht direkt, sondern
188     über Coro::AIO. Eine Map oder andere Daten werden z.B. so geschrieben:
189    
190     if (my $fh = aio_open "$filename~", O_WRONLY | O_CREAT, 0600) {
191     chmod SAVE_MODE, $fh;
192     aio_write $fh, 0, (length $$rdata), $$rdata, 0;
193     aio_fsync $fh;
194     close $fh;
195     aio_rename "$filename~", $filename;
196     } else {
197     warn "FATAL: $filename~: $!\n";
198     }
199    
200     Den Callback läßt man weg, stattdessen werden die Ergebnisse an den
201     Aufrufer zurückgeliefert. Die aktuelle Coroutine wird zwar blockiert,
202     aber andere Coroutinen (z.B. der Server selbst, der Map-Updates an die
203     Spieler liefert) läuft aber ungehindert weiter.
204    
205     =head2 Autor
206    
207     Marc Lehmann <pcg@goof.com>