--- IO-AIO/AIO.pm 2006/10/22 10:33:19 1.58 +++ IO-AIO/AIO.pm 2006/10/23 22:54:27 1.66 @@ -53,13 +53,13 @@ operating system supports. Currently, a number of threads are started that execute your read/writes -and signal their completion. You don't need thread support in your libc or -perl, and the threads created by this module will not be visible to the -pthreads library. In the future, this module might make use of the native -aio functions available on many operating systems. However, they are often -not well-supported (Linux doesn't allow them on normal files currently, -for example), and they would only support aio_read and aio_write, so the -remaining functionality would have to be implemented using threads anyway. +and signal their completion. You don't need thread support in perl, and +the threads created by this module will not be visible to perl. In the +future, this module might make use of the native aio functions available +on many operating systems. However, they are often not well-supported +(Linux doesn't allow them on normal files currently, for example), +and they would only support aio_read and aio_write, so the remaining +functionality would have to be implemented using threads anyway. Although the module will work with in the presence of other threads, it is currently not reentrant, so use appropriate locking yourself, always call @@ -81,7 +81,7 @@ our @EXPORT = qw(aio_sendfile aio_read aio_write aio_open aio_close aio_stat aio_lstat aio_unlink aio_rmdir aio_readdir aio_scandir aio_symlink aio_fsync aio_fdatasync aio_readahead aio_rename aio_link aio_move - aio_group); + aio_group aio_nop); our @EXPORT_OK = qw(poll_fileno poll_cb min_parallel max_parallel max_outstanding nreqs); @IO::AIO::GRP::ISA = 'IO::AIO::REQ'; @@ -354,10 +354,10 @@ you can recurse into (directories or links to them), and ones you cannot recurse into (everything else). -C is a composite request that consists of many sub -requests. C<$maxreq> specifies the maximum number of outstanding aio -requests that this function generates. If it is C<< <= 0 >>, then a -suitable default will be chosen (currently 8). +C is a composite request that creates of many sub requests_ +C<$maxreq> specifies the maximum number of outstanding aio requests that +this function generates. If it is C<< <= 0 >>, then a suitable default +will be chosen (currently 6). On error, the callback is called without arguments, otherwise it receives two array-refs with path-relative entry names. @@ -406,7 +406,7 @@ my $grp = aio_group $cb; - $maxreq = 8 if $maxreq <= 0; + $maxreq = 6 if $maxreq <= 0; # stat once add $grp aio_stat $path, sub { @@ -447,19 +447,21 @@ my ($statcb, $schedcb); my $nreq = 0; + my $statgrp = add $grp aio_group; + $schedcb = sub { if (@$entries) { if ($nreq < $maxreq) { my $ent = pop @$entries; $nreq++; - add $grp aio_stat "$path/$ent/.", sub { $statcb->($_[0], $ent) }; + add $statgrp aio_stat "$path/$ent/.", sub { $statcb->($_[0], $ent) }; } } elsif (!$nreq) { # finished + $statgrp->cancel; undef $statcb; undef $schedcb; - $grp->result (\@dirs, \@nondirs) if $cb; - undef $cb; + $grp->result (\@dirs, \@nondirs); } }; $statcb = sub { @@ -533,6 +535,19 @@ (aio_stat ...), ...; +=item aio_nop $callback->() + +This is a special request - it does nothing in itself and is only used for +side effects, such as when you want to add a dummy request to a group so +that finishing the requests in the group depends on executing the given +code. + +While this request does nothing, it still goes through the execution +phase and still requires a worker thread. Thus, the callback will not +be executed immediately but only after other requests in the queue have +entered their execution phase. This can be used to measure request +latency. + =item IO::AIO::aio_sleep $fractional_seconds, $callback->() *NOT EXPORTED* Mainly used for debugging and benchmarking, this aio request puts one of @@ -560,7 +575,7 @@ =over 4 -=item $req->cancel +=item cancel $req Cancels the request, if possible. Has the effect of skipping execution when entering the B state and skipping calling the callback when @@ -568,6 +583,10 @@ untouched. That means that requests that currently execute will not be stopped and resources held by the request will not be freed prematurely. +=item cb $req $callback->(...) + +Replace (or simply set) the callback registered to the request. + =back =head2 IO::AIO::GRP CLASS @@ -603,13 +622,24 @@ This makes it very easy to create composite requests (see the source of C for an application) that work and feel like simple requests. -The IO::AIO::GRP objects will be cleaned up during calls to +=over 4 + +=item * The IO::AIO::GRP objects will be cleaned up during calls to C, just like any other request. -They can be canceled like any other request. Canceling will cancel not -just the request itself, but also all requests it contains. +=item * They can be canceled like any other request. Canceling will cancel not +only the request itself, but also all requests it contains. + +=item * They can also can also be added to other IO::AIO::GRP objects. + +=item * You must not add requests to a group from within the group callback (or +any later time). -They can also can also be added to other IO::AIO::GRP objects. +=item * This does not harmonise well with C, so best do +not combine C with it. Groups and feeders are recommended for +this kind of concurrency-limiting. + +=back Their lifetime, simplified, looks like this: when they are empty, they will finish very quickly. If they contain only requests that are in the @@ -623,10 +653,10 @@ =over 4 -=item $grp->add (...) - =item add $grp ... +=item $grp->add (...) + Add one or more requests to the group. Any type of L can be added, including other groups, as long as you do not create circular dependencies. @@ -638,6 +668,51 @@ Set the result value(s) that will be passed to the group callback when all subrequests have finished. By default, no argument will be passed. +=item feed $grp $callback->($grp) + +[VERY EXPERIMENTAL] + +Sets a feeder/generator on this group: every group can have an attached +generator that generates requests if idle. The idea behind this is that, +although you could just queue as many requests as you want in a group, +this might starve other requests for a potentially long time. For +example, C might generate hundreds of thousands C +requests, delaying any later requests for a long time. + +To avoid this, and allow incremental generation of requests, you can +instead a group and set a feeder on it that generates those requests. The +feed callback will be called whenever there are few enough (see C, +below) requests active in the group itself and is expected to queue more +requests. + +The feed can queue as many requests as it likes (i.e. C does not +impose any limits). + +If the feed does not queue more requests when called, it will be +automatically removed from the group. + +If the feed limit is C<0>, it will be set to C<2> automatically. + +Example: + + # stat all files in @files, but only ever use four aio requests concurrently: + + my $grp = aio_group sub { print "finished\n" }; + feed_limit $grp 4; + feed $grp sub { + my $file = pop @files + or return; + + add $grp aio_stat $file, sub { ... }; + }; + +=item feed_limit $grp $num + +Sets the feeder limit for the group: The feeder will be called whenever +the group contains less than this many requests. + +Setting the limit to C<0> will pause the feeding process. + =back =head2 SUPPORT FUNCTIONS @@ -704,17 +779,18 @@ =item IO::AIO::min_parallel $nthreads -Set the minimum number of AIO threads to C<$nthreads>. The current default -is C<4>, which means four asynchronous operations can be done at one time -(the number of outstanding operations, however, is unlimited). +Set the minimum number of AIO threads to C<$nthreads>. The current +default is C<8>, which means eight asynchronous operations can execute +concurrently at any one time (the number of outstanding requests, +however, is unlimited). IO::AIO starts threads only on demand, when an AIO request is queued and no free thread exists. -It is recommended to keep the number of threads low, as some Linux -kernel versions will scale negatively with the number of threads (higher -parallelity => MUCH higher latency). With current Linux 2.6 versions, 4-32 -threads should be fine. +It is recommended to keep the number of threads relatively low, as some +Linux kernel versions will scale negatively with the number of threads +(higher parallelity => MUCH higher latency). With current Linux 2.6 +versions, 4-32 threads should be fine. Under most circumstances you don't need to call this function, as the module selects a default that is suitable for low to moderate load. @@ -735,6 +811,8 @@ =item $oldnreqs = IO::AIO::max_outstanding $nreqs +[DEPRECATED] + Sets the maximum number of outstanding requests to C<$nreqs>. If you try to queue up more than this number of requests, the caller will block until some requests have been handled. @@ -743,6 +821,10 @@ queue up many requests in a loop it often improves speed if you set this to a relatively low number, such as C<100>. +This function does not work well together with C's, and their +feeder interface is better suited to limiting concurrency, so do not use +this function. + Under normal circumstances you don't need to call this function. =back @@ -765,7 +847,7 @@ *$sym } -min_parallel 4; +min_parallel 8; END { max_parallel 0; @@ -789,6 +871,19 @@ not been called, while the child will act as if IO::AIO has not been used yet. +=head2 MEMORY USAGE + +Each aio request uses - depending on your architecture - around 128 bytes +of memory. In addition, stat requests need a stat buffer (possibly a few +hundred bytes). Perl scalars and other data passed into aio requests will +also be locked. + +This is now awfully much, so queuing lots of requests is not usually a +problem. + +Each thread needs a stack area which is usually around 16k, sometimes much +larger, depending on the OS. + =head1 SEE ALSO L, L (obsolete).