我想在学习 Raku 的同时对 Python 和 Raku 进行一些比较。
本来我想要一个更大的脚本,但由于差异已经很大,我现在就寻求指导。
我尝试忠实地翻译这个 Python 脚本,同时应用不应该损害性能的 Raku 知识:
from collections import deque
from itertools import count, islice
def primes_wheel():
yield 2
composites = {}
for candidate in count(3, step=2):
prime = composites.pop(candidate, 0)
if prime:
while True:
candidate += prime + prime
if candidate not in composites:
composites[candidate] = prime
break
else:
composites[candidate * candidate] = candidate
yield candidate
def last(itr):
return deque(itr, 1).pop()
LENGTH = 99999
print(last(islice(primes_wheel(), 0, LENGTH)))
我到达了这个:
sub primes_wheel {
my %composite;
gather {
take 2;
for 3,5…* -> $candidate is copy {
my $prime = %composite{$candidate}:delete;
if $prime.defined {
loop {
$candidate += $prime + $prime;
if not %composite{$candidate}:exists {
%composite{$candidate} = $prime;
last;
}
}
}
else {
%composite{$candidate * $candidate} = $candidate;
take $candidate;
}
}
}
}
constant LENGTH = 99999;
say primes_wheel[LENGTH - 1];
结果确实对 Raku 不利(
-OO
对于 Python 来说没有太大区别,但 --optimize=3
使 Raku 变慢):
% hyperfine 'raku primes.raku' 'python -OO primes.py'
Benchmark 1: raku primes.raku
Time (mean ± σ): 4.953 s ± 0.050 s [User: 4.986 s, System: 0.040 s]
Range (min … max): 4.899 s … 5.036 s 10 runs
Benchmark 2: python -OO primes.py
Time (mean ± σ): 291.3 ms ± 13.8 ms [User: 125.2 ms, System: 15.2 ms]
Range (min … max): 266.4 ms … 315.9 ms 10 runs
Summary
python -OO primes.py ran
17.01 ± 0.82 times faster than raku primes.raku
我是否错过了什么或没有以正确的方式使用东西?我希望 Raku 能赶上。我对性能改进和 Rakuisms 都很感兴趣。
在我看来,你应该利用编程语言的优势,而不是试图模仿其他语言的方法。在这种情况下:
constant LENGTH = 99999;
my @primes = (^Inf).grep(*.is-prime);
say @primes[LENGTH - 1];
或者,如果您对两者之间的值并不真正感兴趣:
say (^Inf).grep(*.is-prime).skip(LENGTH - 1).head;
在我的 M1 MacMini 上运行大约需要 0.56 秒。然而,这种管道方法允许使用多个 CPU 来进行超级操作:
say (^Inf).hyper(batch => 2048).grep(*.is-prime).skip(99998).head;
这对我来说大约需要 0.24 秒。减去 0.11 的启动开销,速度大约是原来的 3.5 倍。这在 4 核机器上还算不错。