在Perl中传递一段哈希作为参数

时间:2015-08-08 05:53:12

标签: perl hash slice

我的哈希数据看起来像这样:

my %inputData;
$inputData{'312'} = 'foobar';
$inputData{'112'} = 'qwerty';
$inputData{'232'} = 'test123';
$inputData{'221'} = 'asdfg';

等等。

我使用分叉来分析数据,我使用$ n个分叉。 process()函数启动一个新的fork来进行数据分析,如下所示:

for my $i ( 0 .. $n-1 )
{
    process( ... );
}

如何将哈希引用作为参数传递给包含%inputData切片的process()函数?

例如,如果$ n = 2,循环将运行两次迭代,并且第一次迭代会执行:

my %hashSlice;
$hashSlice{'312'} = 'foobar';
$hashSlice{'112'} = 'qwerty';
process(\%hashSlice);

并在第二次迭代时执行:

my %hashSlice;
$hashSlice{'232'} = 'test123';
$hashSlice{'221'} = 'asdfg';
process(\%hashSlice);

或者,如果$ n = 3,循环将运行三次迭代,并且第一次迭代将执行:

my %hashSlice;
$hashSlice{'312'} = 'foobar';
$hashSlice{'112'} = 'qwerty';
process(\%hashSlice);

在第二次迭代时执行:

my %hashSlice;
$hashSlice{'232'} = 'test123';
process(\%hashSlice);

并在第三次迭代时执行:

my %hashSlice;
$hashSlice{'221'} = 'asdfg';
process(\%hashSlice);

3 个答案:

答案 0 :(得分:3)

我可以建议您不要这样做吗?为什么不使用类似Parallel::ForkManager之类的东西,只为每个键生成一个新的fork - 单独限制并发性。

E.g。

#!/usr/bin/env perl
use strict;
use warnings;
use Parallel::ForkManager;

my $fm = Parallel::ForkManager -> new ( 3 ); 

foreach my $key ( keys %inputData ) {
   $fm -> start and next;
   process ( $inputData{$key} );
   $fm -> finish;
}

$fm -> wait_all_children();

这会将您的并发限制设置为3,但会为每个元素生成一个新的fork,并允许您轻松地扩展'更宽的'只需更改该并发数。

否则,我会考虑切换到使用threads并通过Thread::Queue将元素提供给多个工作线程。

答案 1 :(得分:1)

你不能创建一个较小的哈希作为另一个的子集,而不是像你写的那样以某种方式构建它

最好将整个哈希与要处理的密钥列表一起传递,例如

process( \%input_data, 'foobar', 'qwerty', 'test123')

您可以使用切片来构建较小的哈希,例如

my @keys = ( 'foobar', 'qwerty', 'test123' );
my %subset;
@subset{@keys} = @input_data{@keys};
process(\%subset);

此外,您应该避免使用词汇标识符中的大写字母。大写保留用于全局标识符,例如Package :: Names,如果你也将它们用于局部变量和子程序,可能会发生一些严重的冲突

答案 2 :(得分:0)

如果要解决这个问题,那么从一个公共队列中抓取工作的工作池模型可以更好地工作。 Parallel :: Manager解决方案Sobrique就是一个例子(尽管重用工作者可能更好)。

一个简单的解决方案:

my %data       = ...;
my $num_groups = ...;

my @groups;
my $i = 0;
for my $key (keys(%data)) {
   $groups[$i]{$key} = $data{$key};
   $i = ($i + 1) % $num_groups;
}

可能快一点,特别是对于大输入。

my %data       = ...;
my $num_groups = ...;

our @keys; local *keys = sub { \@_ }->( keys(%data) );
my $r = @keys % $num_groups;
my $group_size = ( @keys - $r ) / $num_groups;
for my $i (0..$num_groups-1) {
   our @group_keys; local *group_keys = sub { \@_ }->(
      splice(@keys, 0, $group_size + ( $i < $r ? 1 : 0 ))
   );
   my %group;
   @group{@group_keys} = @data{@group_keys};
   push @groups, \%group;
}

注意:

  1. our @a; local *a = sub { \@_ }->( LIST );
    

    类似于

    my @a = LIST;
    

    除了@a的元素是LIST返回的实际标量,而不是它们的副本。

  2. 自5.20起,

    my %group;
    @group{@group_keys} = @data{@group_keys};
    push @groups, \%group;
    

    可以写

    push @groups, { %data{@group_keys} };