1

マルチスレッドを使用して IHS ログ ファイルを解析しています。ファイル ハンドルごとに個別のスレッドを割り当て、500 エラーの数をカウントしています。

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;

}

問題は、出力が print Dumper(%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({});が原因のようですが、それを回避する方法がわかりません。

ありがとう!

4

2 に答える 2

1

コードのロジックによると、各値は 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の使用を検討してください。

于 2012-04-30T21:12:40.063 に答える
0
$error_count{$ti} = &share({});

毎回新しいハッシュ参照を割り当ててから、次の行でカウントを増やしています。これを次のように変更します。

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

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

于 2012-04-30T21:13:31.390 に答える