在perl中高效循环浏览2D哈希的方法

问题描述 投票:0回答:1

我正在寻找一种方法来加快我的perl执行速度。我有一个脚本,读取一个文件并创建一个二维哈希(至少有800万个键值对)。然后我根据用户的输入创建了两个独立的哈希,其中包含了2D哈希的第一级和第二级键值。但是当我试图将这些数据组合起来打印出来时,执行速度非常慢。以下是打印数据的代码块(脚本中最耗时的部分)。

open(my $FH_DATA, ">", $report_graph) or die "Cannot open file $!"; 
print $FH_DATA "$HEADER_GRAPH\n";
  foreach my $first_key ( keys %first_level_hash) {
    foreach my $second_key (keys %second_level_hash ) {
      foreach my $rail (@FILTER_BY_RAILS) {
        if( exists $FILTER_BY_RAIL_COMMON{"$first_key.$second_key.$rail"} ) {
          print $FH_DATA " $_ " for @{ $my_2D_hash{$first_key}{$second_key} };
          print $FH_DATA "$rail $second_key $first_key";
          print $FH_DATA "\n";
        }
      }
    }
  }
close($FH_DATA);
print "Finished writing $report_graph\n";

这个嵌套的foreach循环真的很耗费我的执行时间。我一直在不断地看它,现在成了瞎子。任何帮助都是非常感激的。

NYTProfiler的输出。enter image description here

perl optimization hash
1个回答
4
投票

更新   由于问题中的一个关键细节已经更新,所以进行了重大改写。


这段代码去掉了两个嵌套的哈希键,为每个哈希键准备相同的东西。$rail-过滤后的条目。这些涉及到解除引用的哈希查找并不是很自由,而且会增加。由于每个过滤循环中与打印相关的哈希部分都是一样的,所以在外面准备它们

foreach my $first_key ( keys %first_level_hash) {
    foreach my $second_key (keys %second_level_hash ) {
        my @line_elems = @{ $my_2D_hash{$first_key}{$second_key} };
        foreach my $rail (
            grep { exists $FILTER_BY_RAIL_COMMON{"$first_key.$second_key.$_"} }
            @FILTER_BY_RAILS)
        {
            print $FH_DATA " $_ " for @line_elems;
            print $FH_DATA "$rail $second_key $first_key";
            print $FH_DATA "\n";
        }
}

grep 的效率也应该比 if 语句的显式循环。

总的来说,这肯定会有帮助,但如果 @FILTER_BY_RAILS 是小的,那么可能就不会大幅。

这大约是在不能够重新安排操作的情况下可以做到的。一个重大的改进是在之前,也许是在哈希值被填充的时候进行过滤,这样就可以创建一个单独的数据结构,准备打印。 然后循环也可以更有效地解开一些)。

这还是要付出一些代价的,哈希值的速度并不快,而且在大的哈希值上迭代需要周期。


一个小的调整也可以尝试,因为可能更快的是在打印本身

print $FH_DATA ' '.join('  ', @$line).' ';
© www.soinside.com 2019 - 2024. All rights reserved.