目前我有一个需要提取日志的脚本。下面是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;
}
}
}
}
答案 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可能是最好的)。