如何加快这个Perl脚本的grep速度

时间:2015-01-20 05:17:12

标签: bash perl grep

目前我有一个需要提取日志的脚本。下面是Perl代码片段:脚本遍历每个服务器文件夹并grep必要的信息。问题是当日志数量可能很大时,脚本可能需要很长时间才能完成。瓶颈就是这条线:

@leaf_lines = qx($grep -l "stagename = $current_stage" $grep_path| xargs $grep "Keywords")

我想知道是否有办法加快这项行动? 该脚本在每个CPU有8个内核和8G内存的服务器上运行,有没有办法使用这些资源?

my $grep = ($leaflog_zipped) ? "zgrep" : "grep" ;
my %leaf_info;
my @stage = ("STAGE1", "STAGE1", "STAGE3");
foreach my $leaf_dir (@leaf_dir_list){
    my $grep_path = $log_root_dir . "/$leaf_dir/*" ;          
    foreach my $current_stage (@stage){
        my @leaf_lines;
        @leaf_lines = qx($grep -l "stagename = $current_stage" $grep_path| xargs $grep "Keywords"); ## how to improve the grep speed?  
        foreach (@leaf_lines){
            if(...){
                $leaf_info{$current_stage}{xxx} = xxxx;
            }
        }    
    }
}

2 个答案:

答案 0 :(得分:1)

对于初学者 - 我说不要掏出' to grep - perl具有完美的内置模式匹配和正则表达式,并包括预编译正则表达式的功能。

http://perldoc.perl.org/perlop.html#Regexp-Quote-Like-Operators

此外 - 您可以使用线程或分叉相当容易地并行运行perl,这样可以更好地利用CPU资源。

但是我会指出 - 像grep这样的事情通常与CPU有关。如今CPU的速度相当快,文件系统通常要慢很多。您可能会花费更多的时间从磁盘读取数据而不是处理它的数据。

所以可能会给你带来很多悲伤的事情就是你多次grep。

my $grep_path = $log_root_dir . "/$leaf_dir/*" ;          
foreach my $current_stage (@stage)

@stage的每个元素都会触发另一个grep,它会对该目录中的每个文件执行此操作。然后你再次再次

这是一个糟糕的算法,因为你将多次读取每个文件。为什么不这样做:

#could do this with map - I haven't for clarity. 
my %stages;
$stages{'STAGE1'}++;
$stages{'STAGE2'}++;
$stages{'STAGE3'}++;

foreach my $file ( glob $grep_path ) {
    open( my $input_fh, "<", $file ) or die $!;
    while (<$input_fh>) {
        if (m/current_stage/) {
            my ($file_stage) = (
                m/stagename = (\w+)/;
            );
            if ( $stages{$file_stage} ) {
                # do something here
            }
        }
    }
}

那样 - 虽然你必须阅读每个文件 - 你只需要这样做一次。

答案 1 :(得分:0)

是的,当然。只需用GNU Parallel或其他类似的程序替换xargs(在某些Linux系统上有多个名为parallel的程序,所以要注意你拥有哪个; GNU Parallel可能是最好的)。