Переменная экземпляр VS двойной доступ к хеш-ссылке - PullRequest
0 голосов
/ 30 сентября 2010

Изначально я искал быстрый способ доступа к элементу ref-хэша (со значением по умолчанию, если значение недоступно).

Итак, я попробовал следующее:

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 после того, как он напечатал «Done»? Сборка мусора?

Версия Perl: это Perl v5.10.1, созданный для многопоточности MSWin32-x86

Ответы [ 2 ]

5 голосов
/ 30 сентября 2010
  1. Начиная с версии 5.10, вы можете использовать оператор // (определенный-или) для проверки на определенность и назначить значение по умолчанию за один шаг.$result до $hashref->{$key}, если это значение определено, и "NONE" в противном случае.

    2. Больше или меньше.Если это вас беспокоит, шлепните

        use POSIX;
        POSIX::_exit(0);
    

    в конце вашего сценария.Это немедленно завершит ваш скрипт, минуя обычную процедуру закрытия Perl (и любой код, который вы поместили в блоки END { }).Возможно, нет ничего сложного в том, чтобы использовать его в этом сценарии, но обычно не рекомендуется использовать _exit.

2 голосов
/ 30 сентября 2010

Как я уже сказал в комментарии, используйте Benchmark для проведения подобных сравнений. Бенчмарк обрабатывает все подробности о времени проведения тестов и печати отчета.

Еще одна вещь, о которой стоит упомянуть, это то, что ваш тест не проверяет то, что вы думаете. Ваши тесты выдвигают значения на @preciousvalues1 и @preciousvalues2. Каждая итерация теста добавляет примерно 500 результатов к одному из массивов. Поскольку вы не очищаете массивы между итерациями, вы получаете два массива, каждый из которых содержит около 12,5 миллионов записей. Я предполагаю, что это приводит вас к обмену и ведет к медленному, полуслучайному времени выполнения. Это также является причиной задержки при выходе из вашей программы. Вы выделили огромное количество оперативной памяти для этих структур. 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 не выполняет вызов функции, который используют две другие реализации.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...