2012-04-30 21 views
1

我正在使用多线程来解析IHS日志文件。我为每个文件句柄分配一个单独的线程并计算500个错误的数量。使用Perl线程共享2维哈希

sub parse_file { 

    my $file = shift; 
    my @srv = split /\//,$file; 
    my $filename = $srv[$#srv]; 
    my $TD = threads->tid(); 

    $sem->down; 
    print "Spawning thread $TD to process file \"$filename\"\n" if ($verbose); 
    $rTHREADS++; 
    $TIDs{$TD} = 1; 
    $sem->up; 

    open (FH, "$file") || die "Cannot open file $file $!\n"; 
    while (<FH>){  
    if (/^(\d{13}).*?(\d{3}) [\-0-9] \d+ \d+ \//){ 
     my $epoch = $1/1000; 
     my $http_code = $2; 
     my $ti = scalar localtime($epoch); 
     $ti =~ s/(\d{2}):\d{2}:\d{2}/$1/; 

     if ($http_code eq '500'){ 
     unless (exists $error_count{$ti} && exists $error_count{$ti}{$http_code}){ 
      lock(%error_count); 
      $error_count{$ti} = &share({}); 
      $error_count{$ti}{$http_code}++; 
     } 
     } 
    } 
    } 
    close (FH); 

    $sem->down; 
    print "Thread [$TD] exited...\n" if ($verbose); 
    $rTHREADS--; 
    delete $TIDs{$TD}; 
    $sem->up; 

} 

问题是,输出看起来像这样使用打印自卸车(%http_count):

$VAR1 = 'Mon Apr 30 08 2012'; 
$VAR2 = { 
      '500' => '1' 
     }; 
$VAR3 = 'Mon Apr 30 06 2012'; 
$VAR4 = { 
      '500' => '1' 
     }; 
$VAR5 = 'Mon Apr 30 09 2012'; 
$VAR6 = { 
      '500' => '1' 
     }; 
$VAR7 = 'Mon Apr 30 11 2012'; 
$VAR8 = { 
      '500' => '1' 
     }; 
$VAR9 = 'Mon Apr 30 05 2012'; 
$VAR10 = { 
      '500' => '1' 
     }; 
$VAR11 = 'Mon Apr 30 07 2012'; 
$VAR12 = { 
      '500' => '1' 
     }; 
$VAR13 = 'Mon Apr 30 10 2012'; 
$VAR14 = { 
      '500' => '1' 
     }; 
$VAR15 = 'Mon Apr 30 12 2012'; 
$VAR16 = { 
      '500' => '1' 
     }; 

工作了79秒

500计数每个日期总是被设置为1。我无法让它显示正确的计数。看起来$error_count{$ti} = &share({});是罪魁祸首,但我不知道如何绕过它。

谢谢!

+1

使用'print Dumper(\%http_count)'来避免将散列转储为许多单独的标量值。 – Borodin

+0

谢谢兄弟!这里的所有评论都非常有帮助! – waltz777

回答

0
$error_count{$ti} = &share({}); 

您每次都指定一个新的散列引用,然后在下一行中递增计数。更改为:

$error_count{$ti} ||= &share({}); 

这将有条件地初始化散列表成员。准确地说,当值为undef0或空字符串时,它会生效。

+0

这个伎俩。谢谢! – waltz777

1

根据您的代码中的逻辑,每个值只会递增一次:当它还不存在于%error_count中时。

要每次都通过增加价值,但创建仅在需要脚手架(你有共享的集装箱做的,而不是依靠自动激活),使用

if ($http_code eq '500') { 
    lock(%error_count); 

    unless (exists $error_count{$ti} && exists $error_count{$ti}{$http_code}) { 
    $error_count{$ti} = &share({}); 
    } 

    $error_count{$ti}{$http_code}++; 
} 

如果锁定整个哈希是太宽刷,看看用Thread::Semaphore来代替。

+0

谢谢!尽管使用上面的代码,但它是最有帮助的,但我无法删除if条件,并且让它散列任何http代码,因为只有最新的代码需要。 – waltz777

+0

我并不是要你去除外部条件。除了这个特定的块以外,其他一切都保持不变。 –