Jason
Jason

Reputation: 12283

Why does perl execute a command take longer than running the command alone?

When I run the command

montage -background black -geometry +0+0 -mode Unframe -tile ${num_digits}x1 $filelist gif:- > ~/temp/count.gif

It takes 0.1 seconds to execute (I used time montage...).

When I put that command in my perl cgi script

print LOG "starting montage\n";
open(GRFX,
    "montage -background black -geometry +0+0 -mode Unframe -tile ${num_digits}x1 $filelist gif:- |"
);
print LOG "finish montage\n";
print <GRFX>;
print LOG "finish output\n";
close(GRFX);

The time between "finish montage" and "finish output" is 6 seconds!!

If I run the cgi script from the command line it takes 0.1 seconds. But from within Apache it takes the 6 seconds, even when accessed with a browser on the same computer as Apache (so it is not the Internet slowing things down, also, all other pages load fast regardless of whether the browser is on the same computer).

The resulting gif file generated by montage is 1.7k.

Any ideas why this is so slow when run within Apache?

The only header output is print "Content-type: image/gif\n\n";

Upvotes: 2

Views: 499

Answers (1)

Sinan &#220;n&#252;r
Sinan &#220;n&#252;r

Reputation: 118128

You are using print <GRFX>; to print the output, reading all the lines of output from the piped shell command.

LINES is the operative word here. Presumably, the trailing sequence of bytes does not end in a newline, and therefore Perl is waiting around for it. Eventually, it times out.

You can set local $/ = 4096 to read 4096 byte chunks at a time. Then, output using print while <GRFX>.

It would be good form to also binmode both GRFX and STDOUT so you don't get bit by problems like this. See also my blog post on a related question.

I would be tempted to re-write your code like this (untested):

sub output_image {
    my $num_digits = shift;
    my $filelist = shift;

    print LOG "starting montage\n";

    my @cmd = (
        montage => qw(
        -background black
        -geometry +0+0
        -mode Unframe
        -tile),
        "${num_digits}x1",
        split(/ /,$filelist),
        'gif:-'
    );

    open my $GRFX, '-|', @cmd
        or die "Failed to open pipe: $!";

    {
        local $/ = 4096;
        binmode $GRFX;
        binmode STDOUT;
        print while <$GRFX>;
    }

    close $GRFX
        or die "Failed to close pipe: $!";

    print LOG "finish montage\n";
}

Upvotes: 1

Related Questions