Подтвердить что ты не робот

Какую производительность мы можем ожидать по мере того, как будут реализованы версии Perl 6?

Каждый раз, когда я загружаю новую копию Rakudo Perl 6, я запускаю следующее выражение, чтобы получить представление о его текущей производительности:

say [+] 1 .. 100000;

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

use List::Util 'sum';

print sum(1 .. 100000), "\n";

или в Ruby (также почти мгновенно):

(1 .. 100000).inject(0) {|sum,x| sum+x}

Переписывание выражения как Perl6 loop заканчивается примерно в два раза быстрее, чем уменьшение диапазона, но для простого вычисления это еще очень заметная задержка (более секунды):

my $sum;
loop (my $x = 1; $x <= 100000; $x++) {$sum += $x}

Итак, мой вопрос: какие аспекты реализации Perl6 вызывают эти проблемы производительности? И должно ли это улучшаться со временем, или это накладные расходы, неудачный побочный эффект модели "все является объектом", которую использует Perl6?

И, наконец, как насчет конструкции loop быстрее, чем оператор сокращения [+]? Я бы подумал, что цикл приведет к более полному ops, чем сокращение.

EDIT:

Я бы принял ответы mortiz и hobbs, если бы мог. То, что все обрабатывается как вызов метода, более непосредственно отвечает на вопрос, почему [+] работает медленно, поэтому его можно получить.

4b9b3361

Ответ 1

Еще одна вещь, которую вы должны понять об отсутствии оптимизации, это то, что она усугубляется. Большая часть Rakudo написана на Perl 6. Так, например, оператор [+] реализован методом Any.reduce (Any.reduce с $expression установленным в &infix:<+>), который имеет внутренний цикл

for @.list {
    @args.push($_);
    if (@args == $arity) {
        my $res = $expression.(@args[0], @args[1]);
        @args = ($res);
    }
}

Другими словами, это чисто-Perl-реализация execute, которая сама управляется Rakudo. Таким образом, не только код, который вы видите, не оптимизируется, но и код, который вы не видите, чтобы ваш код выполнялся, также не оптимизируется. Даже экземпляры оператора + самом деле являются вызовами методов, так как, хотя оператор + в Num реализован Parrot, в Rakudo еще нет ничего, что могло бы распознать, что у вас есть два Num и оптимизировать вызов метода, поэтому существует полная динамическая диспетчеризация. до того, как Ракудо найдет multi sub infix:<+>(Num $a, Num $b) и поймет, что все, что он на самом деле делает, это код операции добавления. Это разумное оправдание для того, чтобы быть в 100-1000 раз медленнее, чем Perl 5 :)

Обновление 23.08.2010

Больше информации от Джонатана Уортингтона о видах изменений, которые должны произойти с объектной моделью Perl 6 (или, по крайней мере, с точки зрения ее концепции Ракудо), чтобы ускорить процесс, сохранив при этом Perl 6 "все - вызовы методов" природы.

Обновление 1/10/2019

Так как я вижу, что это все еще привлекает внимание... за эти годы Rakudo/MoarVM получили JIT, вкладывание, динамическую специализацию и массу работы многими людьми, оптимизирующими каждую часть системы. В результате большинство из этих вызовов методов могут быть "скомпилированы" и иметь практически нулевые затраты времени выполнения. Perl 6 набирает в сотни или тысячи раз быстрее по многим тестам, чем в 2010 году, а в некоторых случаях он быстрее, чем Perl 5.

В случае проблемы с суммой в 100 000, с которой начался вопрос, Rakudo 2018.06 все еще немного медленнее, чем Perl 5.26.2:

$ time perl -e 'use List::Util 'sum'; print sum(1 .. 100000), "\n";' >/dev/null

real    0m0.023s
user    0m0.015s
sys     0m0.008s

$ time perl6 -e 'say [+] 1 .. 100000;' >/dev/null

real    0m0.089s
user    0m0.107s
sys     0m0.022s

Но если мы амортизируем стоимость запуска, выполняя код 10000 раз, мы увидим другую историю:

$ time perl -e 'use List::Util 'sum'; for (1 .. 10000) { print sum(1 .. 100000), "\n"; }' > /dev/null

real    0m16.320s
user    0m16.317s
sys     0m0.004s

$ time perl6 -e 'for 1 .. 10000 { say [+] 1 .. 100000; }' >/dev/null

real    0m0.214s
user    0m0.245s
sys     0m0.021s

Perl6 использует на несколько сотен миллисекунд больше, чем Perl5 при запуске и компиляции, но затем он выясняет, как выполнить фактическое суммирование примерно в 70 раз быстрее.

Ответ 2

Есть действительно разные причины, почему Ракудо настолько медленный.

Первая и, возможно, самая важная причина в том, что Rakudo еще не делает оптимизаций. Текущие цели - это больше изучить новые возможности и стать более надежными. Вы знаете, они говорят: "Сначала сделайте это, а затем сделайте это правильно, а затем сделайте это быстро".

Вторая причина заключается в том, что попугай пока не предлагает компиляции JIT, а сборщик мусора - не самый быстрый. Планируется компилятор JIT, и люди работают над ним (предыдущий был вырван из-за того, что он был только i386 и кошмар для обслуживания). Есть также мысли о переносе Rakudo на другие виртуальные машины, но это наверняка ждет до конца июля.

В конце концов, никто не может действительно сказать, насколько быстро будет реализована полная оптимизированная реализация Perl 6 до тех пор, пока у нас ее не будет, но я ожидаю, что она будет намного лучше, чем сейчас.

Кстати, случай, который вы указали, [+] 1..$big_number может быть выполнен для запуска в O (1), потому что 1..$big_number возвращает диапазон, который является интроспективным. Таким образом, вы можете использовать формулу суммы для случая [+] Range. Снова это то, что можно было бы сделать, но это еще не сделано.

Ответ 3

Это, конечно, не потому, что все это объект, потому что это верно и на многих других языках (например, Ruby). Нет причин, по которым Perl 6 должен был бы быть величинами медленнее, чем другие языки, такие как Perl 5 или Ruby, но факт в том, что Rakudo не так зрел, как perl или CRuby. Оптимизации скорости еще не было.

Ответ 4

Я представил их в Конкурс языков Fefe в декабре 2008 года. wp.pugs.pl - это буквальный перевод примера Perl 5, wp.rakudo.pl намного старше. У меня две программы, потому что они реализуют разные подмножества спецификации. В то же время информация об устаревании устарела. Источники:

#!/usr/bin/env pugs
# Pugs: <http://pugs.blogs.com/> <http://pugscode.org/>
# prerequisite: ghc-6.8.x, not 6.10.x
# svn co http://svn.pugscode.org/pugs/
# perl Makefile.PL
# make
# if build stops because of haskeline, do:
#   $HOME/.cabal/bin/cabal update ; $HOME/.cabal/bin/cabal install haskeline

# learn more: <http://jnthn.net/papers/2008-tcpw-perl64danoob-slides.pdf>

my %words;

for =<> {
    for .split {
        %words{$_}++
    }
}

for (sort { %words{$^b} <=> %words{$^a} }, %words.keys) {
    say "$_ %words{$_}"
}

#!/usr/bin/env perl6
# Rakudo: <http://rakudo.org/> <http://www.parrot.org/download>
# svn co http://svn.perl.org/parrot/trunk parrot
# perl Configure.pl
# make perl6

# Solution contributed by Frank W. & Moritz Lenz
# <http://use.perl.org/~fw/journal/38055>
# learn more: <http://jnthn.net/papers/2008-tcpw-perl64danoob-slides.pdf>

my %words;

$*IN.lines.split(/\s+/).map: { %words{$_}++ };

for %words.pairs.sort: { $^b.value <=> $^a.value } -> $pair {
    say $pair
}

Это были результаты в 2008 году:

$ time ./wp.pugs.pl < /usr/src/linux/COPYING > foo

real    0m2.529s
user    0m2.464s
sys     0m0.064s

$ time ./wp.rakudo.pl < /usr/src/linux/COPYING > foo

real    0m32.544s
user    0m1.920s
sys     0m0.248s

Сегодня:

$ time ./wp.pugs.pl < /usr/src/linux/COPYING > foo

real    0m5.105s
user    0m4.898s
sys     0m0.096s

$ time ./wp.rakudo.pl < /usr/src/linux/COPYING > foo
Divide by zero
current instr.: '' pc -1 ((unknown file):-1)
Segmentation fault

real    0m3.236s
user    0m0.447s
sys     0m0.080s

Поздние добавления: сбой был рассмотрен на Почему я получаю ошибки "делить на нуль" , когда пытаюсь запустить мой script с помощью Rakudo?. Программа Rakudo неэффективна, см. комментарии ниже и http://justrakudoit.wordpress.com/2010/06/30/rakudo-and-speed/.

Ответ 5

Учитывая, что теперь ваш тестовый пример оптимизирован для алгоритма O (1), который возвращается почти мгновенно, и что похоже почти на несколько оптимизаций в неделю,
Я ожидаю улучшения во всем мире.

$ perl6 -e 'say [+] 1..10**1000; say now - INIT now'
5000000000000000000000000000000000000000000000 ...
0.007447

Даже если это не было специально для диапазонов, это все еще довольно быстро, чем было. Теперь ваш тестовый расчет составляет менее одной пятой секунды.

$ perl6 -e 'say [+] (1..100000).list; say now - INIT now'
5000050000
0.13052975