1

我有一个工作 perl 脚本,它扫描一个目录并使用 imgsize http://dktools.sourceforge.net/imgsize.html来获取 png 文件的宽度等。有没有人有任何加快这个过程的提示(现在,每 1000 个文件平均需要 5 分钟)?我只是想知道代码是否可以通过某种方式进行优化。谢谢。

use strict;
use warnings;

use File::Find;

my @files;
my $directory = '/Graphics/';
my $output_file = '/output_file';
my $max_height = 555;
my $count = 0;

open ( OUTPUT, '>>', $output_file );

find( \&wanted, $directory );

foreach my $file ( @files ) {
        if ( $file =~ /\.png$/ ) {
                my $height = `imgsize $file | cut -d\'\"\' -f4`;
                if ( $height > $max_height ) {
                        print OUTPUT "$file\n";
                }

                $count++;

                my $int_check = $count/1000;
                if ( $int_check !~ /\D/ ) {
                        print "processed: $count\n";
                }
        }
}

print "total: $count\n";
close ( OUTPUT );
exit;

sub wanted {
  push @files, $File::Find::name;
  return;
}

解决方案:原来我能够使用该Image::Info模块。我从每 5 分钟处理 1000 个图像变为每12 秒处理一次。如果有人感兴趣,这是相关的代码片段:

 use Image::Info qw(image_info);

    foreach my $file ( @files ) {
            if ( $file =~ /\.png$/ ) {
                    my $output = image_info($file);
                    my $height = ${$output}{height};

                    if ($height > $max_height) {
                            print OUTPUT "$file\n";
                    }

                    $count++;

                    my $int_check = $count/1000;
                    if ( $int_check !~ /\D/ ) {
                            print "processed: $count\n";
                    }
            }
    }
4

2 回答 2

8

您显示的 Perl 代码可能不是罪魁祸首。您可以使用Devel::NYTProf 对其进行分析,就像@choroba 所说的那样。但我敢打赌,大部分时间都来自为每个图像(imgsizecut)分叉两个外部进程。您应该查看 Perl 模块,这些模块可以在不运行任何外部进程的情况下检索图像的高度。像Image::Info这样的模块浮现在脑海中。

于 2012-11-07T16:38:16.890 回答
2

在循环中启动外部进程通常是让事情进展缓慢的好方法。启动另一个过程需要大量成本,如果您为每张图像都这样做,您很快就会注意到成本。您也在调用cut,这意味着每次循环都会调用两次。

因此,第一步是cut使用本地 Perl 字符串操作进行操作,从而消除每个循环启动一个进程。

不幸的是,完全消除流程成本的唯一方法是在流程中完成所有工作,这意味着您需要一个可以从 Perl 调用的库,它可以读取图像并获取它们的大小。我没有尝试过,但Perl::ImageMagick可能值得一看,我相信还有其他的。

您也可以尝试使用fork或 线程拆分您自己的进程,并让每个子进程并行执行部分负载,但您可能会遇到系统上的 I/O 可用性问题。

于 2012-11-07T16:41:33.113 回答