如何在 Raku 比较方面提高性能?

pri*_*tor 7 performance primes generator raku

我想在学习 Raku 的同时对 Python 和 Raku 进行一些比较。

\n

本来我想要一个更大的脚本,但由于差异已经很大,我现在就寻求指导。

\n

我尝试忠实地翻译这个 Python 脚本,同时应用不应该损害性能的 Raku 知识:

\n
from collections import deque\nfrom itertools import count, islice\n\n\ndef primes_wheel():\n    yield 2\n    composites = {}\n    for candidate in count(3, step=2):\n        prime = composites.pop(candidate, 0)\n        if prime:\n            while True:\n                candidate += prime + prime\n                if candidate not in composites:\n                    composites[candidate] = prime\n                    break\n        else:\n            composites[candidate * candidate] = candidate\n            yield candidate\n\n\ndef last(itr):\n    return deque(itr, 1).pop()\n\n\nLENGTH = 99999\n\nprint(last(islice(primes_wheel(), 0, LENGTH)))\n
Run Code Online (Sandbox Code Playgroud)\n

我到达了这个:

\n
sub primes_wheel {\n    my %composite;\n\n    gather {\n        take 2;\n        for 3,5\xe2\x80\xa6* -> $candidate is copy {\n            my $prime = %composite{$candidate}:delete;\n            if $prime.defined {\n                loop {\n                    $candidate += $prime + $prime;\n                    if not %composite{$candidate}:exists {\n                        %composite{$candidate} = $prime;\n                        last;\n                    }\n                }\n            }\n            else {\n                %composite{$candidate * $candidate} = $candidate;\n                take $candidate;\n            }\n        }\n    }\n}\n\nconstant LENGTH = 99999;\n\nsay primes_wheel[LENGTH - 1];\n
Run Code Online (Sandbox Code Playgroud)\n

结果确实对 Raku 不利(-OO对 Python 来说没有太大区别,但是--optimize=3使 Raku 变慢):

\n
% hyperfine \'raku primes.raku\' \'python -OO primes.py\'\nBenchmark 1: raku primes.raku\n  Time (mean \xc2\xb1 \xcf\x83):      4.953 s \xc2\xb1  0.050 s    [User: 4.986 s, System: 0.040 s]\n  Range (min \xe2\x80\xa6 max):    4.899 s \xe2\x80\xa6  5.036 s    10 runs\n\nBenchmark 2: python -OO primes.py\n  Time (mean \xc2\xb1 \xcf\x83):     291.3 ms \xc2\xb1  13.8 ms    [User: 125.2 ms, System: 15.2 ms]\n  Range (min \xe2\x80\xa6 max):   266.4 ms \xe2\x80\xa6 315.9 ms    10 runs\n\nSummary\n  python -OO primes.py ran\n   17.01 \xc2\xb1 0.82 times faster than raku primes.raku\n
Run Code Online (Sandbox Code Playgroud)\n

我是否错过了什么或没有以正确的方式使用东西?我希望 Raku 能赶上。我对性能改进和 Rakuisms 都感兴趣。

\n
\n

代码翻译问题?

\n

不是翻译问题:

\n
\n

[\xe2\x80\xa6] 标签中有很多问题要求将 [\xe2\x80\xa6] 代码转换为 [\xe2\x80\xa6]

\n
\n

我自己进行了转换,这很有趣!在这里我问为什么我的结果如此慢(即我如何才能更快地得到它)以及我是否使用正确的方式构建(即导致速度减慢的东西)。

\n

我还说过我愿意听到 Rakuisms 来改进它,这不是代码翻译。

\n

@Karl Knechtel:我什至可以完全省略 Python 部分,就好像不是翻译一样。这将是同样的问题,也许那时你就会看到它。但我决定保留它,以便答案更接近它。这也是为什么我不接受伊丽莎白的回答,尽管它表明了你应该做什么对生产代码做什么。我有一种感觉,我的 Raku 做错了什么\xe2\x80\x94 至少我希望如此。我希望得到一个答案来发现这一点并让我更深入地理解。SO是关于学习,对吗?

\n

话虽如此,“不清楚你要问什么”或链接中的 \xe2\x80\x9cneeds 调试详细信息\xe2\x80\x9d均不适用于此处,恕我直言。

\n

Eli*_*sen 8

在我看来,您应该利用编程语言的优势,而不是试图模仿其他语言的方法。在这种情况下:

constant LENGTH = 99999;
my @primes = (^Inf).grep(*.is-prime);
say @primes[LENGTH - 1];
Run Code Online (Sandbox Code Playgroud)

或者,如果您对两者之间的值并不真正感兴趣:

say (^Inf).grep(*.is-prime).skip(LENGTH - 1).head;
Run Code Online (Sandbox Code Playgroud)

在我的 M1 MacMini 上运行大约需要 0.56 秒。然而,这种管道方法允许使用多个 CPU 进行超级操作:

say (^Inf).hyper(batch => 2048).grep(*.is-prime).skip(99998).head;
Run Code Online (Sandbox Code Playgroud)

这对我来说大约需要 0.24 秒。减去 0.11 的启动开销,速度大约是原来的 3.5 倍。这对于 4 核机器来说还算不错。

  • 哇,令人印象深刻的是那里!我需要一个有效的 LSP 来帮助提高可发现性。你是对的,我会在生产代码中使用提供的功能。但我觉得这不再是一个忠实的翻译(就像将一些 Python 计算卸载到 C 扩展一样)。 (3认同)