变量instanciation VS双哈希引用访问

时间:2010-09-30 15:30:49

标签: perl

最初,我一直在寻找一种快速访问哈希引用元素的方法(如果没有值可用,则使用默认值)。

所以我尝试了以下内容:

use strict;
use warnings;
use DateTime;
my $hashref = { };
for (0..249) {
  my $lIdx = $_ * 2;
  $hashref->{"MYKEY$lIdx"} = "MYVAL$lIdx";
}

sub WithVariable{
    my $result = $hashref->{"MYKEY$_[0]"};
    return defined $result ? $result : "NONE";
}

sub WithoutVariable{
    return defined $hashref->{"MYKEY$_[0]"} ? $hashref->{"MYKEY$_[0]"} : "NONE";
}
$|++;
my @preciousvalues1 = ();
my @preciousvalues2 = ();
my $dt = DateTime->now;
for (1..25000) { for (0..498) { push @preciousvalues1, WithVariable($_) } }
my $lag = DateTime->now - $dt;
print "With a variable: ", $lag->seconds, "\n";
$dt = DateTime->now;
for (1..25000) { for (0..498) { push @preciousvalues2, WithoutVariable($_) } }
$lag = DateTime->now - $dt;
print "Without a variable: ", $lag->seconds, "\n";

print "Done\n";

但结果似乎是随机的,perl似乎在打印“Done”之后做了很多事情,并且需要永远退出。

我的问题是:

  1. 如果没有找到值,那么允许以默认值访问存储在哈希值中的值的函数的整洁实现是什么?
  2. 打印“完成”之后,perl究竟做了什么?垃圾收集?
  3. Perl版本:这是为MSWin32-x86-multi-thread构建的perl,v5.10.1

2 个答案:

答案 0 :(得分:5)

  1. 从版本5.10开始,您可以使用//(已定义或)运算符来测试已定义的值,并在一个步骤中指定默认值。
  2. $result = $hashref->{$key} // "NONE"
    如果定义了该值,则

    $result设置为$hashref->{$key},否则设置为"NONE"

    2.或多或少。如果它困扰你,打一个

        use POSIX;
        POSIX::_exit(0);
    

    在脚本的末尾。这将立即终止您的脚本,绕过Perl的正常关闭例程(以及您放入END { }块的任何代码)。在此脚本上使用它可能不是什么大问题,但使用_exit通常不是最佳做法。

答案 1 :(得分:2)

正如我在评论中所说,使用Benchmark进行这些比较。 Benchmark处理测试计时和打印报告的所有细节。

值得一提的另一件事是你的测试没有测试你的想法。您的测试会将值推送到@preciousvalues1@preciousvalues2。每次测试迭代都会向其中一个阵列添加大约500个结果。由于您没有在迭代之间清除数组,因此您最终得到两个数组,每个数组包含 1250万条目。我想这会让你开始交换,并导致你进行缓慢的,半随机的执行时间。这也是退出程序延迟的原因。你已经为这些结构分配了大量的RAM。 Perl希望正确地拆除它们,并确保触发任何析构函数或END块。

这是一个清理版本的测试,专注于哈希访问。我添加了mobrule的解决方案进行比较。

use strict;
use warnings;
use Benchmark qw(cmpthese);


my $hashref = { };
for (0..249) {
  my $lIdx = $_ * 2;
  $hashref->{"MYKEY$lIdx"} = "MYVAL$lIdx";
}

sub WithVariable{
    my $result = $hashref->{"MYKEY$_[0]"};
    return defined $result ? $result : "NONE";
}

sub WithoutVariable{
    return defined $hashref->{"MYKEY$_[0]"} ? $hashref->{"MYKEY$_[0]"} : "NONE";
}

cmpthese( 25000, {
    "With Var" => sub {
        my @vals;
        push @vals, WithVariable($_) for 0..498;
    },
    "Without Var" => sub {
        my @vals;
        push @vals, WithoutVariable($_) for 0..498;
    },
    "Mobrule" => sub {
        my @vals;
        push @vals, $hashref->{"MYKEY$_"} // 'NONE' for 0..498;
    }
} );

在我的系统上有以下结果:

              Rate    With Var Without Var     Mobrule
With Var    1382/s          --         -0%        -49%
Without Var 1389/s          1%          --        -49%
Mobrule     2700/s         95%         94%          --

很明显,mobrule的解决方案更快,而且其他两个实现之间只有微小的差别。最大的区别是mobrule的解决方案不会执行其他两个实现使用的函数调用。