Сравнение строк или поиск хеша быстрее в Perl? - PullRequest
2 голосов
/ 15 сентября 2009

У меня есть некоторый код, который в одной части будет выполняться много, и мне интересно, какой путь является более эффективной реализацией. Я буду использовать цикл for для симуляции части, которую исполняют много:

вариант A:

my %sections = (
    'somestring1' => 1,
    'somestring2' => 1,
    'somestring3' => 1,
    'somestring4' => 1
);

for (0..10000)
{
    # $element is chosen at random
    $namespace = $element if $sections{$element};
}

вариант B:

for (0..10000)
{
    # $element is chosen at random
    $namespace = $element if ($element eq'somestring1' || 
                            $element eq'somestring2' ||
                            $element eq'somestring3' ||
                            $element eq'somestring4');
}

Может кто-нибудь оценить это или узнать ответ, так как я не знаком с инструментами для сравнения.

Этот код, вероятно, не имеет смысла в этом контексте, но на самом деле это то, что мне нужно использовать.

Ответы [ 5 ]

17 голосов
/ 15 сентября 2009

Используйте функцию cmpthese из модуля Benchmark

use strict;
use warnings;
use Benchmark qw'cmpthese';

my %sections = (
    somestring1 => 1,
    somestring2 => 1,
    somestring3 => 1,
    somestring4 => 1
);

my @elements = map { 'somestring' . int(1 + rand(10)) } 1 .. 100;

my $namespace;

cmpthese(100000, {
    hash_value => sub {
        foreach my $element (@elements) {
            $namespace = $element if $sections{$element};
        }
    },
    hash_exists => sub {
        foreach my $element (@elements) {
            $namespace = $element if exists $sections{$element};
        }
    },
    string_cmp => sub {
        foreach my $element (@elements) {
            $namespace = $element if (
                $element eq'somestring1' ||
                $element eq'somestring2' ||
                $element eq'somestring3' ||
                $element eq'somestring4');
        }
    },
});

Мои результаты (запуск Perl 5.10 на WinXP):

               Rate  string_cmp  hash_value hash_exists
string_cmp  18932/s          --        -44%        -50%
hash_value  33512/s         77%          --        -12%
hash_exists 38095/s        101%         14%          --

Таким образом, поиск хеша на 77% быстрее, чем сравнение каскадных строк, а проверка на наличие хеша вместо значения (как предположил Адам Беллер) еще на 14% быстрее.

5 голосов
/ 15 сентября 2009

Я предполагаю, что первая версия с exists будет быстрее, не говоря уже о том, что она более читабельна и удобна в обслуживании.

for (0..10000)
{
    # $element is chosen at random
    $namespace = $element if exists $sections{$element};
}

Простая проверка на наличие ключа хеша быстрее, чем получение его значения для сравнения, поэтому используйте exists.

4 голосов
/ 15 сентября 2009

Механизм поиска хеша значительно быстрее.

3 голосов
/ 15 сентября 2009

Возможно, сейчас самое время познакомиться с инструментами бенчмаркинга, такими как модуль CPAN Benchmark .

0 голосов
/ 24 мая 2017

Тест Майкла Кармана хорош, но к настоящему моменту результаты уже устарели, поэтому люди, не использующие его на своей машине, могут ошибиться. Итак, точно такой же тест (всего в 10 раз больше случаев, чтобы получить более последовательные результаты) на Mac Pro с Mac OS X и Perl 5.24.1:

               Rate  string_cmp hash_exists  hash_value
string_cmp  54142/s          --        -28%        -32%
hash_exists 74850/s         38%          --         -7%
hash_value  80192/s         48%          7%          --

Однако на AWS с CentOS 7 / Perl 5.24.0 мы получаем:

string_cmp  70373/s          --        -24%        -25%
hash_value  92851/s         32%          --         -1%
hash_exists 93545/s         33%          1%          --

Итак, я бы сказал, протестируйте свою собственную машину, но, похоже, в настоящее время такая возможность не дает никаких преимуществ (на моем Mac с последним Perl она даже заметно медленнее в этом конкретном тесте - и даже в других тестах).

Одна вещь, которая мне не нравится в тесте, это то, что он довольно произвольно выбирает сравнение 4 равенств с проверкой хеша. Не смущайтесь, если у нас есть только один элемент в хэше, поэтому мы сравниваем с одним полученным равенством (на моем Mac Pro / Perl 5.24.1):

hash_value  119474/s          --         -1%        -14%        -34%
hash_exists 121065/s          1%          --        -12%        -33%
grep        138122/s         16%         14%          --        -23%
string_cmp  180180/s         51%         49%         30%          --

Я добавил туда один grep, который избегает цикла foreach для сравнения. Итак, одно равенство, очевидно, быстрее, чем проверка хеша, но не в два раза быстрее, поэтому, если вы можете заменить только два равенства проверкой хеша, вы получите преимущество:

string_cmp  104167/s          --        -15%        -17%
hash_value  121951/s         17%          --         -2%
hash_exists 125000/s         20%          2%          --

Однако это с хешем, предварительно созданным вне цикла, как в оригинальном примере. Что если мы создадим хэш в каждом цикле тестирования? То есть у вас есть пара значений, которые вы хотите проверить на наличие в массиве, стоит ли создавать хеш с ними? Я не буду утомлять вас дополнительными результатами, поскольку вы можете обнаружить, что они различаются на вашей машине, но ответ таков: для 2 значений «это зависит» (так что, возможно, вам не стоит беспокоиться), но для 3 или более вы должны сделать это.

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