Почему разница в производительности в + = против +?

Отладка некоторого кода закончилась проверкой различий в утверждениях, таких как $counter=$counter + 1; против $counter+=1;

my $run=True;
my $counter=0;
my $sup=Supply.interval(1);
my $tap= $sup.tap({
    $run=$_ < 10;
});
{
    while $run {
        #$counter+=1;
        $counter=$counter + 1;
    }
    $tap.close;
    say "Iterations per second: {$counter/(now - ENTER now)}"; #
}

Я получаю примерно на 20% больше итераций в секунду для $counter=$counter+1 по сравнению с $counter+=1;

Что происходит на фоне, это так по-другому?

РЕДАКТИРОВАТЬ:

Интересно, что при использовании массива и гипероператоров производительность значительно увеличивается при использовании +=.

например, @[email protected]>>+<<@value; vs @counter>>+=<<@value; Я получаю примерно 2,8 раза итераций цикла, используя >>+=<< с массивами из 10_000 элементов.

Насколько я могу судить по time cmd, минимальное параллельное выполнение в любом случае минимально (общее количество пользователей + система находится в пределах 2% от реального времени).

Любое понимание того, как/почему это было бы здорово. Спасибо!

Ответ 1

Я показал ваш тест на:

my $a = 0; for ^10_000_000 { $a += 1 }

против:

my $a = 0; for ^10_000_000 { $a = $a + 1 }

Если вы запустите эти примеры в профилировщике с помощью perl6 --profile -e '...', то вы увидите, что разница действительно находится в диапазоне 20%. Единственное, что действительно отличается, - это общее количество кадров: 49935579 для += 1 и 39932197 для = $a + 1.

Основное различие (до каких-либо оптимизаций) заключается в том, что += проходит через метаопуть. Он не определен как отдельный оператор, поэтому ему нужно создать оператор на лету, взяв в качестве параметра исходный оператор (&infix:<+>) и Callable из него Callable.

FWIW, я рад видеть, что в настоящее время разница составляет всего 20%: это было не так давно, когда что-либо, включающее метаопы, было как минимум в 2 раза медленнее :-)