在perl中填充哈希的最快方法

时间:2017-11-23 16:10:15

标签: performance perl hash populate

我正在尝试从大约564k行的文件中填充perl中的哈希值,代码执行时间为1.6~2.1秒,而C#中的等效值大约需要0.8秒才能完成。在Perl中有没有更好的方法呢?

到目前为止我已尝试过:

# 1 - this version take ~ +1.6 seconds to fill the hash from file with ~ 564000
my %voc;
open(F,"<$voc_file");
while(defined(my $line=<F>)) {
    chomp($line);
    $voc{$line} = 1;
}
close(F);

和这个

# 2 - this version take ~ +2.1 seconds to fill the hash from file with ~ 564000
my %voc;
my @voc_keys;
my @array_of_ones;
open(F,"<$voc_file");
my $voc_keys_index = 0;
while(defined(my $line=<F>)) {
    chomp($line);
    $voc_keys[$voc_keys_index] = $line;
    $array_of_ones[$voc_keys_index] = 1;
    $voc_keys_index ++;
}
@voc{@voc_keys} = @array_of_ones;
close(F);

在c#中,我正在使用:

var voc = new Dictionary<String, int>();
foreach (string line in File.ReadLines(pathToVoc_file))
{
    var trimmedline = line.TrimEnd(new char[] { '\n' });
    voc[trimmedline] = 1;
}

只需700~800毫秒

2 个答案:

答案 0 :(得分:3)

绝对避免将1存储为数据并使用存在可以节省时间和内存。你可以通过从循环中删除块来实现更多功能:

my %voc;
open(F,"<$voc_file");
chomp, undef $voc{$_} while <F>;
close(F);

基准测试结果(使用20个字符行):

Benchmark: running ikegami, original, statementmodifier, statementmodifier_undef for at least 10 CPU seconds...
   ikegami: 10 wallclock secs ( 9.54 usr +  0.46 sys = 10.00 CPU) @  2.10/s (n=21)
  original: 10 wallclock secs ( 9.62 usr +  0.45 sys = 10.07 CPU) @  2.09/s (n=21)
statementmodifier: 10 wallclock secs ( 9.61 usr +  0.48 sys = 10.09 CPU) @  2.18/s (n=22)
statementmodifier_undef: 11 wallclock secs ( 9.85 usr +  0.48 sys = 10.33 CPU) @  2.23/s (n=23)

基准:

use strict;
use warnings;
use Benchmark 'timethese';

my $voc_file = 'rand.txt';

sub check {
    my ($voc) = @_;
    unless (keys %$voc == 564000) {
        warn "bad number of keys ", scalar keys %$voc;
    }
    chomp(my $expected_line = `head -1 $voc_file`);
    unless (exists $voc->{$expected_line}) {
        warn "bad data";
    }
    return;
}

timethese(-10, {
    'statementmodifier' => sub {
        my %voc;
        open(F,"<$voc_file");
        chomp, $voc{$_} = 1 while <F>;
        close(F);
        #check(\%voc);
        return;
    },
    'statementmodifier_undef' => sub {
        my %voc;
        open(F,"<$voc_file");
        chomp, undef $voc{$_} while <F>;
        close(F);
        #check(\%voc);
        return;
    },
    'original' => sub {
        my %voc;
        open(F,"<$voc_file");
        while(defined(my $line=<F>)) {
            chomp($line);
            $voc{$line} = 1;
        }
        close(F);
        #check(\%voc);
        return;
    },
    'ikegami' => sub {
        my %voc;
        open(F,"<$voc_file");
        while(defined(my $line=<F>)) {
            chomp($line);
            undef $voc{$line};
        }
        close(F);
        #check(\%voc);
        return;
    },
});

(原来的错误答案取而代之。)

答案 1 :(得分:1)

当然C#会更快。

您可以通过替换

节省一点时间和一些记忆
$voc{$line} = 1;  ...  if ($voc{$key}) { ... }  ...

undef $voc{$line};  ...  if (exists($voc{$key})) { ... }  ...