gpt4 book ai didi

performance - `now` 在 1000 万次迭代循环中变慢

转载 作者:行者123 更新时间:2023-12-03 15:08:02 28 4
gpt4 key购买 nike

我有一个 SnowFlake script for Python ,然后我将其转换为 Raku模块,并调用它 10,000,000 次,它非常慢(文件 test.raku):

use IdWorker;

my $worker = IdWorker.new(worker_id => 10, sequence => 0);
my @ids = gather for (1...10000000) { take $worker.get_id() };

my $duration = now - INIT now;
say sprintf("%-8s %-8s %-20s", @ids.elems, Set(@ids).elems, $duration);
正如@codesections 的回答所说,它是 now这需要很多时间。
Python 大约需要 12 秒,而 Raku 需要几分钟。我怎样才能解决这个问题?
这个空的 for 循环大约需要 0.12 秒:
for (1...10000000) {
;
}
并调用 get_id()$worker需要 分钟 :
for (1...10000000) {
$worker.get_id();
}

最佳答案

我相信这里的问题不是来自构建数组,而是来自 now本身——这似乎异常缓慢。
例如,这段代码:

no worries; # skip printing warning for useless `now`
for ^10_000_000 { now }
say now - INIT now;
也需要几分钟才能运行。这让我觉得这是一个错误,我将打开一个问题 [编辑:我找到了 rakudo/rakudo#3620在这个问题上。好消息是已经有修复计划。] 因为您的代码调用 now在每次迭代中多次,这个问题对你的循环影响更大。
除此之外,还有一些其他领域可以加快此代码的速度:
首先,使用隐式返回(即将 return new_id; 更改为 new_id ,并对使用 return 的其他地方进行类似更改)通常会稍微快一些/让 JIT 优化得更好一些。
二、线路
my @ids = gather for (1...10000000) { take $worker.get_id() };
使用 gather 有点浪费/ take (它增加了对惰性列表的支持,只是一个更复杂的结构)。您可以将其简化为
my @ids = (1...10000000).map: { $worker.get_id() };
(不过,这仍然构造了一个中间 Seq。)
第三——从性能影响来看,这个影响更大,尽管从代码更改的角度来看,它可能尽可能小——是更改 (1...10000000)进入 (1..10000000) .区别在于 ...sequence operator..range运算符(operator)。与 Ranges 相比,序列具有一些超能力(如果您好奇,请参阅文档),但在这样的循环中迭代要慢得多。
不过,这些都是小问题。我相信 now的表现是最大的问题。 now 的长期解决方案变慢是为了修复它(我们正在努力解决这个问题!)不过,作为一种临时解决方法,如果您不介意使用比通常建议的用户代码略低的级别,您可以使用 nqp::time_n 获取当前时间的浮点秒数。使用它会使您的 get_timestamp方法看起来像:
method get_timestamp() {
use nqp;
(nqp::time_n() * 1000).Int;
}
有了这个解决方法和我上面建议的其他重构,您的代码现在在我的机器上执行大约 55 秒 - 仍然没有我希望 Raku 快,但比我们开始的地方好一个数量级。

关于performance - `now` 在 1000 万次迭代循环中变慢,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/66565399/

28 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com