我正在使用多线程来解析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({});
是罪魁祸首,但我不确定如何绕过它。
谢谢!
答案 0 :(得分: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。
答案 1 :(得分:0)
$error_count{$ti} = &share({});
您每次都要分配一个新的哈希引用,然后在下一行中增加计数。将其更改为:
$error_count{$ti} ||= &share({});
这将有条件地初始化哈希表成员。确切地说,当值为undef
,0
或空字符串时,它将生效。