0

共享散列散列的一种方法是声明每一级散列,例如:

my %hash : shared;
$hash{test} = &share({});

但是如果第一级密钥的数量无法预测或太多以至于您无法声明每个密钥怎么办。

像下面的代码:

#!/usr/bin/perl -w
use strict;
use threads;
use threads::shared;

my %counts :shared;
my $infile = $ARGV[0];
open my $inf, "$infile";

while(my $inline = <$inf>){
    chomp($inline);
    my @entry = split(/\t/,$inline);
    my $t = threads->create('WORK',@entry)->join;
}

foreach my $i(sort {$a cmp $b} keys %counts){
    foreach my $j(sort {$a cmp $b} keys %{$counts{$i}}){
        print "$i\t$j\t$counts{$i}{$j}\n";
    }
}

sub WORK{
    my @work = @_;
    $counts{$work[0]}{$work[1]}++;
}

和测试集:

apple   pie
banana  icecream
orange  juice
mango   juice
mango   pie
mango   pie
......

该脚本将通过警告您“某些行的共享标量的无效值”来停止。那么有没有一种方法可以共享 %counts 和 %{$counts{KEY1}}?假设我不知道我将在测试集第一列观察到多少种水果,输出应该是这样的:

apple    pie      1
banana   icecream 1
mango    juice    1
mango    pie      2
orange   juice    1
4

1 回答 1

1

在您的脚本中,您依赖于autovivification:哈希和数组,一旦被引用,就会立即出现。这通常有效。它不会在你use threads(默认情况下不共享自动激活的数据结构)。如果需要,我们可以简单地自己创建子哈希。这将使您的WORK

sub WORK{
  unless (exists $counts{$_[0]}) {
    my %anon :shared;
    $counts{$_[0]} = \%anon;
  }
  $counts{$_[0]}{$_[1]}++;
}

或者

sub WORK { ($counts{$_[0]} //= do{my %a :shared; \%a})->{$_[1]}++ }

或类似的。我还删除了@_数组的相当无用的复制。

请注意,您的示例甚至不需要线程。因为你做

my $t = threads->create('WORK',@entry)->join;

这几乎完全等同于

my $t = WORK(@entry);

此外,join返回线程的返回值(在这种情况下是增量之前的计数,因为它是最后一条语句的值),而不是线程对象。

于 2012-10-11T21:46:05.677 回答