qw/deprecated::smartmatch/;
use Benchmark qw(:all);
use Switch '__';
my $x = 5;
my @arr = ('zero', 'one', 'two', 'three');
my %hash = (
0 => 'zero',
1 => 'one',
2 => 'two',
3 => 'three',
);
cmpthese(-1, +{
'array lookup' => sub {
my $y = $arr[$x] // 'too many';
},
'hash lookup' => sub {
my $y = $hash{$x} // 'too many';
},
"?:" => sub {
my $y =
!$x ? 'zero'
: $x == 1 ? 'one'
: $x == 2 ? 'two'
: $x == 3 ? 'three'
: 'too many'
;
},
"&& ||" => sub {
my $y =
!$x && 'zero'
|| $x == 1 && 'one'
|| $x == 2 && 'two'
|| $x == 3 && 'three'
|| 'too many'
;
},
"and or" => sub {
my $y =
(!$x and 'zero'
or $x == 1 and 'one'
or $x == 2 and 'two'
or $x == 3 and 'three'
or 'too many'
);
},
"elsif" => sub {
my $y;
if ( !$x ) { $y = 'zero' }
elsif ($x == 1) { $y = 'one' }
elsif ($x == 2) { $y = 'two' }
elsif ($x == 3) { $y = 'three' }
else { $y = 'too many' }
},
"sub return if ..." => sub {
my $y = (sub {
return 'zero' if !$x;
return 'one' if 1 == $x;
return 'two' if 2 == $x;
return 'three' if 3 == $x;
return 'too many';
})->();
},
"given" => sub {
my $y;
given($x) {
$y = 'zero' when !$_;
$y = 'one' when 1;
$y = 'two' when 2;
$y = 'three' when 3;
default { $y = 'too many' }
}
},
"switch" => sub {
my $y;
(sub {
switch($x) {
case !__ { $y = 'zero' }
case 1 { $y = 'one' }
case 2 { $y = 'two' }
case 3 { $y = 'three' }
else { $y = 'too many' }
}
})->();
},
"{}" => sub {
# Тут выражения вычисляются все, а не последовательно,
# поэтому раскрывают частный случай
my $y = +{
0 => 'zero',
1 => 'one',
2 => 'two',
3 => 'three',
}->{$x} // 'too many';
},
});
Если поставить в каждом тесте my $x = int rand 5;, то результаты будут не по одному кейсу...
Да, но и точности и смысла в бенчмарке не будет. В одном варианте будет больше вариантов с лучшим случаем - $x == 0 - зашли в первый if и пошли дальше, а в других больше худших случаев - $x > 3.
В cmpthese можно указать количество повторений: 100_000, тогда $x в каждом случае будет от 0 до 4 одинаковое количество раз
Если нужно для всех, то может лучше сделать цикл от 0 до 4?
Это - тоже частный случай. В реальности цифры ведь будут приходить в разброс. В perl и библиотеке libc, которую он использует для вывода, в драйвере ос, который отвечает за ввод-вывод процессов и в терминале могут быть кеши и различный код с неизвестным поведением, который выполняется разное время. (Тут же ещё say тестируется) Поэтому, если нужно тестировать только условия, то нужно убрать say, но тогда присваивать результат глобальной переменной или оптимизатор вообще может убрать код. Интерпретатор может иметь оптимизацию цикла и условия в последовательном цикле могут работать иначе
В моем примере выше я как раз убрал say и вызов do в придачу.
Если есть оптимизация цикла, то она будет работать для всех случаев.
так ты предлагаешь ещё int rand протестировать
У них O(1) - значит никак не повлияют )
Поскольку в этом месте никто не встрял, попробую встрять я ) Есть вполне документированная фича у функции srand, а именно, после вызова: srand число; все последующие вызовы rand будут генерировать одни и те же последовательные значения (для разного "число" будут разные последовательности, разумеется, еще от компа зависит - какие) https://perlbanjo.com/54aaef218a соответственно, и с помощью rand мы можем сгенерить одни и те же тестовые последовательности для каждой функции (тут пример был ошибочный, нужно придумать как именно)
Идея хорошая, но в cmpthese - малореализуемая
"?:" => sub { state $init = undef; if (!$init) { $init = srand 2; } my $x = int rand 5; say !$x ? 'zero' : $x == 1 ? 'one' : $x == 2 ? 'two' : $x == 3 ? 'three' : 'too many' ; }, "&& ||" => sub { state $init = undef; if (!$init) { $init = srand 2; } my $x = int rand 5; say !$x && 'zero' || $x == 1 && 'one' || $x == 2 && 'two' || $x == 3 && 'three' || 'too many' ; }, # и т.д. так работает, только не забыть в скрипте use v5.10;
Можно короче. state $init; $init//=srand(2); Можно и так state $init=srand(2); Но это багоопасная привычка и так лучше не делать
Был такой кейс, когда после fork вызывался rand - и в обоих процессах выдавал одинаковое число. Выход - сначала srand, который в обоих процессах инициирует разные стартовые последовательности.
В обоих не нужно, достаточно в одном, при этом не важно в каком
Ну это понятно. ))
Что-то не пойму, где ошибся. А если не ошибся, то почему rand() выдаёт разные числа даже в 5.8 https://perlbanjo.com/d27c0dd6f4
Я кстати тоже сталкивался, причём под mod_perl, лет десять назад. Так что перл не очень старый должен быть. Но там эта хрень была завязана на внешний модуль какой-то. Надо будет поковыряться в своих архивах
Обсуждают сегодня