代码之家  ›  专栏  ›  技术社区  ›  Eric Strom

随着Perl6实现的成熟,我们可以期望什么样的性能提高?

  •  27
  • Eric Strom  · 技术社区  · 14 年前

    Each time I have downloaded a new copy of Rakudo Perl 6, I have run the following expression just to get an idea of its current performance:

    say [+] 1 .. 100000;
    

    And the speeds have been increasing, but each time, there is a noticeable delay (several seconds) for the calculation. As a comparison, something like this in Perl 5 (or other interpreted languages) returns almost instantly:

    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}
    

    So my question is, what aspects of the Perl6 implementation are causing these performance issues? And should this improve with time, or is this overhead an unfortunate side effect of the "everything is an object" model that Perl6 is using?

    最后,那 构造比 [+] 还原运算符?我认为这个循环将导致比减少更多的总操作。

    编辑:

    我都接受 mortiz S和 hobbs 's answers if I could. That everything is a being handled as a method call more directly answers why [+] 就是慢慢来,这样一个人就能得到它。

    5 回复  |  直到 6 年前
        1
  •  16
  •   hobbs    6 年前

    另一件你必须理解的关于缺乏优化的事情是 复合的 . 大量的rakudo被写入 在Perl 6中 . 例如, [+] 该方法实现了运算符 Any.reduce (打电话) $expression 设置为 &infix:<+> ,它的内环

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

    in other words, a pure-perl implementation of reduce, which itself is being run by Rakudo. So not only is the code you can 看见 没有得到优化,代码 不要 看到了吧,让你的代码运行起来也不是 优化。即使是 + 运算符实际上是方法调用,因为尽管 + 运算符开启 Num 是由Parrot实施的,Rakudo还没有发现你有两个 号码 并优化掉方法调用,所以在rakudo找到之前有一个完整的动态调度 multi sub infix:<+>(Num $a, Num $b) and realizes that all it's really doing is an 'add' opcode. It's a reasonable excuse for being 100-1000x slower than Perl 5 :)

    更新日期:2010年8月23日

    More information from Jonathan Worthington on the kinds of changes that need to happen with the Perl 6 object model (or at least Rakudo's conception of it) to make things fast while retaining Perl 6's "everything is method calls" nature.

    更新1/10/2019

    Since I can see that this is still getting attention... over the years, Rakudo/MoarVM have gotten JIT, inlining, dynamic specialization, and of work by many people optimizing every part of the system. The result is that most of those method calls can be "compiled out" and have nearly zero runtime cost. Perl 6 scores hundreds or thousands of times faster on many benchmarks than it did in 2010, and in some cases it's faster than Perl 5.

    In the case of the sum-to-100,000 problem that the question started with, Rakudo 2018.06 is still a bit slower than 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 uses a few hundred more milliseconds than perl5 on startup and compilation, but then it figures out how to do the actual summation around 70 times faster.

        2
  •  21
  •   moritz    14 年前

    Rakudo这么慢的原因有很多。

    The first and maybe most important reason is that Rakudo doesn't do any optimizations yet. The current goals are more explore new features, and to become more robust. You know, they say "first make it run, then make it right, then make it fast".

    The second reason is that parrot doesn't offer any JIT compilation yet, and the garbage collector isn't the fastest. There are plans for a JIT compiler, and people are working on it (the previous one was ripped out because it was i386 only and a maintenance nightmare). There are also thoughts of porting Rakudo to other VMs, but that'll surely wait till after end of July.

    In the end, nobody can really tell how fast a complete, well-optimized Perl 6 implementation will be until we have one, but I do expect it to be much better than now.

    顺便说一句你引用的案例 [+] 1..$big_number 可以在O(1)中运行,因为 1..$big_number 返回一个可内省的范围。所以你可以用一个和公式 [+] Range 案例。这也是可以做的,但还没有完成。

        3
  •  5
  •   Leon Timmermans    14 年前

    当然不是因为 一切都是一个物体

        4
  •  3
  •   Community CDub    8 年前

    我把这些提交给 Fefe's language competition 2008年12月。 wp.pugs.pl 是Perl5示例的直译, wp.rakudo.pl is far more sixier. I have two programs because the two implement a different subset of the spec. Build information is outdated meanwhile. 资料来源:

    #!/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
    

    晚点补充:车祸已经在 Why do I get 'divide by zero` errors when I try to run my script with Rakudo? . Rakudo项目效率低下,请参见 comments below http://justrakudoit.wordpress.com/2010/06/30/rakudo-and-speed/ .

        5
  •  3
  •   Brad Gilbert    9 年前

    考虑到现在你的测试用例是 optimized to an O(1) algorithm 这几乎是立即返回,而且看起来几乎每周都有几个优化;
    我希望四周的表现都有很大的改善。

    $ 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