3

我正在编写一个生成多个大型数组散列(HoA)数据结构的脚本。我正在尝试优化我的脚本,因为目前它需要花费大量时间来运行。

我做了一些基准测试。我设法使脚本执行大约。@_通过使用数组引用并通过直接使用而不是将其复制到变量中来减少子例程调用开销,速度提高了 3.5 倍。我还删除了不必要的子程序和多余的变量声明。尽管有这些改进,我还是想让代码运行得更快。

在我的脚本开始时,我解析一个大文件以生成两个 HoA 数据结构。这些关于哈希引用的方法中哪一种是最可行和最有效的?HoA 看起来像这样:

%HoA = (
    'C1' =>  ['1', '3', '3', '3'],
    'C2' => ['3','2'],
    'C3' => ['1','3','3','4','5','5'],
    'C4'  => ['3','3','4'],
    'C5' => ['1'],
);

选项1

在我解析文件时生成 HoA(见下文)。最后将数组的哈希值放入哈希引用中。

my $hash_ref = \%HoA;

选项 2

解析文件,使 HoA 中的每个键都有一个指向 array_ref 的值。最后将数组的哈希值放入哈希引用中。

===============

我觉得选项 2 是一个很好的方法,但我该怎么做呢?

这是我目前的做法。

use strict; use warnings;
open(F1, "file.txt") or die $!;
my %HoA = ();
    while (<F1>){
    $_=~ s/\r//;
    chomp;
    my @cols = split(/\t/, $_);

    push( @{$HoA{$cols[0]}}, @cols[1..$#cols]);
 }
close F1;

我需要一个高效的数据结构来帮助我快速查找值和键。此外,我需要能够尽可能高效地将键值(数组)、键和 HoA 本身多次传递到子例程中。

4

4 回答 4

4
  • 不要使用全局变量,包括文件句柄。
  • 您声明%HoA并从未使用过。
  • 您声明$HoA_ref但从未使用过它。
  • $HoA没有声明就使用了。始终使用use strict; use warnings;
  • 为什么要创建一个您不需要的引用并最终多次取消引用它?
  • 没有理由为您刚刚创建的哈希分配一个空列表。my %HoA = ();很傻。
  • 还不如结合s///chomp;
  • $_不需要时省略,或者使用有意义的变量名。

上述所有内容和其他一些改进已获得:

use strict;
use warnings;

open(my $fh, '<', 'file.txt') or die $!;

my %HoA;
while (<$fh>){
    s/\r?\n\z//;
    my ($key, @cols) = split /\t/;
    push @{ $HoA{$key} }, @cols;
}
于 2013-04-01T06:59:46.960 回答
2

我的经验是,最好尽可能使用参考。一些附加说明:

  1. 如果你需要这个,$_=~ s/\r//;为了 Windows eol 兼容性,那么你需要一个更好的 perl 构建。ActiveState 通常是最健壮的。 chomp应该处理终端 cr/lf,或者更确切地说,读取的文件应该已经将 cr/lf 对转换为仅 lf。

  2. Perlshift是 O(1) 并且非常快。你可以在这里利用它来发挥你的优势。

  3. 你无法提前知道什么是最快的。选择基准是唯一的出路。

  4. 尝试单独读取输入文件而不进行处理。一旦作业受 I/O 限制,优化就不再有用了。

这是我要开始的:

 open(F, "file.txt") or die $!;
 my $h = {};
 while (<F>){
   chomp;
   my @cols = split "\t";
   my $key = shift @cols;
   push @{$h->{$key}}, @cols;
 }
 close F;
于 2013-04-01T06:21:55.233 回答
1

我认为这就是您在示例中尝试做的事情。

open(my $fh, "<", "file.txt") or die $!;
my $HoA_ref = {}; # ref will return a HASH 
while (my $line = <$fh>) {
    $line =~ s/\r//;
    chomp $line;
    my @cols = split(/\t/, $line);

    # shift off first element in the list to use 
    # as the key
    my $key = shift(@cols);
    # set value to an array ref of whatever 
    # is left in the list.
    $HoA_ref->{$key} => [@cols];
}
close <$fh>;

值得注意的是,$key如果在循环文件时出现多次,它将被覆盖。

于 2013-04-01T06:19:04.630 回答
1

由于您有大文件,而不是使用 while 循环,我建议您使用模块File::Slurp进行完整的文件 slurping 。

File::Slurp read_file 函数尝试使用 sysread(检查read_file 源代码)调用绕过 perl I/O。

my $text = read_file( $file ) ;

于 2013-04-01T07:52:22.803 回答