2012-04-30 3 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초

항상 1로 설정 될 때마다 최신의 500 카운트했다. 적절한 수를 표시 할 수 없습니다. 그것은 성명을 $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

코드의 논리에 따르면 각 값은 정확하게 한 번 증가합니다 (아직 %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

나는 바깥 쪽 조건문을 지우지 않았다. 이 특별한 덩어리를 제외하고는 다른 모든 것이 동일하게 유지됩니다. –