2012-04-30 10 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' 
     }; 

仕事を日付ごと500カウントは常に1に設定されている79秒に

を取りました。私はそれが適切なカウントを表示することができません。ステートメント$error_count{$ti} = &share({});が原因だと思われますが、私はそれを回避する方法がわかりません。

ありがとうございます!

+1

'print Dumper(\%http_count)'を使用して、ハッシュを多くの別々のスカラー値としてダンプしないようにします。 – Borodin

+0

ありがとう!ここのコメントはすごく役立ちます! – waltz777

答えて

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

あなたが次の行のカウントをインクリメントし、それぞれの時期に新しいハッシュリファレンスを割り当てています。これを次のように変更します。

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

ハッシュテーブルメンバーを条件付きで初期化します。正確には、値がundef,0または空の文字列の場合に有効になります。

+0

これはトリックでした。ありがとう! – waltz777

1

コードのロジックによれば、各値は正確に1回インクリメントされます(まだ%error_countに存在しない場合)。ハッシュ全体をロックすることは広すぎるaがある場合

は毎回を通じて値をインクリメントが、(あなたはむしろautovivificationに頼るよりも、共有コンテナとしなければならない)だけで、必要に応じて足場を作成し、

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

私は、あなたが外側の条件文を削除することを意味しませんでした。この特定のチャンクを除いて他のすべては同じままです。 –

関連する問題