Search code examples
perlmojolicious

understanding Mojo::IOLoop recurring and subprocess


I have some JPG files in './photo ' directory, I use Image::Thumbnail and GD to create thumbnails of them.

code1.pl:

use Image::Thumbnail;
my $dir = './photos' ;
opendir(DIR, $dir) or die "Can not open dir\n";
my @files = grep { /\.JPG/ && -f "$dir/$_" ; } readdir( DIR );
closedir DIR;

my $t1 = time;
for my $f (@files){
    print $f, "\n";
    my $t = new Image::Thumbnail(
        module     => 'GD',
        size       => 200,
        create     => 1,
        input      => $dir . '/' . $f,
        outputpath => $dir . '/' . 'thumb_' . $f,
    );
}

print "Time used: ", time-$t1, "\n";

I test 9 photos with each size about 4M,the code1.pl running 9~10s in total.

code2.pl: (use Mojo::IOLoop,in fact I want to process photos uploaded by client in mojo web app )

use Image::Thumbnail;
use Mojo::Base -strict;
use Mojo::IOLoop;

my $dir = './photos' ;
opendir(DIR, $dir) or die "Can not open dir\n";
my @files = grep { /\.JPG/ && -f "$dir/$_" ; } readdir( DIR );
closedir DIR;

my $t1 = time;

my $loop = Mojo::IOLoop->singleton;
$loop->recurring( 
    0 => sub {
        $loop->stop and return unless my $f = shift @files;
        print $f, "\n";
        my $t = new Image::Thumbnail(
            module     => 'GD',
            size       => 200,
            create     => 1,
            input      => $dir . '/' . $f,
            outputpath => $dir . '/' . 'thumb_' . $f,
        );
    } 
);

$loop->on(finish => sub {
  print "Time used: ", time-$t1, "\n";
});

$loop->start;

This code2.pl can run correctly, but the time consumed seems unchanged.

code3.pl: (I change recurring to subprocess)

use Image::Thumbnail;
use Mojo::Base -strict;
use Mojo::IOLoop;

my $dir = './photos' ;
opendir(DIR, $dir) or die "Can not open dir\n";
my @files = grep { /\.JPG/ && -f "$dir/$_" ; } readdir( DIR );
closedir DIR;

my $t1 = time;

my $loop = Mojo::IOLoop->singleton;
$loop->subprocess( 
    map{
        sub {
            #$loop->stop and return unless my $f = shift @files;
            my $f = $_ ;
            my $t = new Image::Thumbnail(
                module     => 'GD',
                size       => 200,
                create     => 1,
                input      => $dir . '/' . $f,
                outputpath => $dir . '/t_' . $f,
            );
            print $f, "\n";
        }
    } @files
);

$loop->on(finish => sub {
  print "Time used: ", time-$t1, "\n";
});

$loop->start;

the code3.pl raise error:

Subprocesses do not support fork emulation at C:/Perl/site/lib/Mojo/IOLoop.pm line 152.
shell returned 255

I use activeperl on winXP, (v5.20.2), look forward for your help.


Solution

  • First of all, Mojo::IOLoop::Subprocess is used incorrectly in your third example. The documentation states that run method needs to be given 2 subroutines, first is one that will be executed in "background" and should return resulting values, if any, which will be processed by a second subroutine. In your case you should create new subprocess object for each element in @files.

    Relatively the error code3.pl returns, it looks like Mojo::IOLoop or at least your version don't work on Perl compiled with d_pseudofork flag. Consider using Strawberry Perl on WinXP as it is open source distribution and better optimized for Windows.