🚀 go-pugleaf

RetroBBS NetNews Server

Inspired by RockSolid Light RIP Retro Guy

Article View: comp.lang.perl.misc
Article #268

Re: Most efficient method to call a system routine and capture it's output

#268
From: Benjamin Goldberg
Date: Fri, 19 Jul 2002 22:23
88 lines
4105 bytes
Ralph SOBEK wrote:
[snip]
>         What is the most efficient method to call a system routine
> repeatedly and capture it's short output?

If you *must* call it repeatedly, then you could probably start multiple
instances of the program simultaneously, with a pipe coming from each,
and after they're all started, read the pipes and collect the results.

>         Supposedly, in loop:
> 
> #1      system @cmd;
>
> is efficient.

It runs the command, sending the command's stdout to perl's stdout, and
having the command read from perl's stdin, and send's the command's
stderr to perl's stderr.  Since perl isn't doing the IO, it's reasonably
efficient.

>  But using backquotes:
> 
> #2      (my $sum = `@cmd 2>/dev/null`) =~ s/\s+.*$//;
> 
> captures the output correctly, but is horrendously slow,

First, this causes the command's stdout to be captured by perl.  Since
IO is slow, this isn't especially fast.

Second, due to needing the redirection, perl can't run the command
directly, but must instead start a shell, which parses the "2>..." part,
and *then* starts your program.

The extra step of starting a shell will of course slow things down.

> if repeated a couple of thousand times.  For 35,000 files count about
> SIX hours!
> 
>         Is there a possibility to prepare the fork in #1 in such a way
> as to recover the forks output afterwards?  It may help to know that
> the output consists only of two numbers.
> 
>         In fact, in the above I am using File::Find to recursively
> checksum a file structure.  @cmd[0] = '/usr/ucb/sum' and @cmd[1] is
> the file path.

Well, now that we know that you're running the 'sum' command, which will
take *multiple* file arguments on the commandline, if you ask it to, we
can suggest that collect bunches of filenames, then call 'sum' *once*
for that bunch.

That is, consider the speed difference between:
   find . -exec /usr/ucb/sum {} \;
And:
   find . | xargs /usr/ucb/sum

The first runs 'sum' once for each file.  The second collects bunches of
filenames, and runs 'sum' once for each bunch.

>         Furthermore, in #2 there is the additional problem that the
> shell causes with unusual file names.

Then don't invoke the shell, or don't let the filenames be seen by the
shell.

Consider this:
use IPC::Open3;
use File::Spec;
local (*DEVNULL, *FILENAMES, *CHECKSUMS);
open( DEVNULL, ">>", File::Spec->devnull )
   or die "Couldn't open /dev/null: $!";
open( FILENAMES, "-|", "find ." )
   or die "Couldn't spawn find process: $!";
my $sums = open3(
   "<&FILENAMES", \*CHECKSUMS, ">&DEVNULL",
   "xargs", "/usr/ucb/sum" );
while( <CHECKSUMS> ) {
   my ($crc, $size, $name) = split ' ', $_, 3;
   ... do stuff ...
}
waitpid( $sums, 0 ) or die horribly;
$? and die horribly;
__END__
[untested]

-- 
tr/`4/ /d, print "@{[map --$| ? ucfirst lc : lc, split]},\n" for
pack 'u', pack 'H*', 'ab5cf4021bafd28972030972b00a218eb9720000';
Technical Details
Message-ID: <3D38914B.EA1E832A@earthlink.net>
Path: arc1-ca.pugleaf.net!archiver1.google.com!news1.google.com!newsfeed.stanford.edu!newsmi-us.news.garr.it!newsmi-eu.news.garr.it!NewsITBone-GARR!fu-berlin.de!uni-berlin.de!dialup-209.246.73.192.dial1.newyork1.level3.NET!not-for-mail
References: <ausn2ib8ny.fsf@irit.irit.fr> <aud6tjbw4d.fsf@irit.irit.fr>

Show Full Headers
Complete Article Headers
X-Google-Language: ENGLISH,ASCII-7-bit
X-Google-Thread: 112333,d48ce9f80ca98172
X-Google-Attributes: gid112333,public
X-Google-Thread: fa0ae,4cb838d93b34e411
X-Google-Attributes: gidfa0ae,public
X-Google-ArrivalTime: 2002-07-19 15:22:51 PST
Path: arc1-ca.pugleaf.net!archiver1.google.com!news1.google.com!newsfeed.stanford.edu!newsmi-us.news.garr.it!newsmi-eu.news.garr.it!NewsITBone-GARR!fu-berlin.de!uni-berlin.de!dialup-209.246.73.192.dial1.newyork1.level3.NET!not-for-mail
From: Benjamin Goldberg <goldbb2@earthlink.net>
Newsgroups: comp.lang.perl.misc,fr.comp.lang.perl
Subject: Re: Most efficient method to call a system routine and capture it's output
Date: Fri, 19 Jul 2002 18:23:07 -0400
Lines: 88
Message-ID: <3D38914B.EA1E832A@earthlink.net>
References: <ausn2ib8ny.fsf@irit.irit.fr> <aud6tjbw4d.fsf@irit.irit.fr>
NNTP-Posting-Host: dialup-209.246.73.192.dial1.newyork1.level3.net (209.246.73.192)
Mime-Version: 1.0
Content-Type: text/plain; charset=us-ascii
Content-Transfer-Encoding: 7bit
X-Trace: fu-berlin.de 1027117369 28701532 209.246.73.192 (16 [87109])
X-Mailer: Mozilla 4.04 [en] (Win95; I)