gpt4 book ai didi

python - 在本地命名空间中编写代码比在 PyPy3 中的全局中慢

转载 作者:行者123 更新时间:2023-12-04 10:14:25 24 4
gpt4 key购买 nike

我用 bash 的时间函数测试了下面的代码。

# test_local.py
def main():
n = 10 ** 7
mod = 10 ** 9 + 7
x = 0
for i in range(n):
x += i
x %= mod


if __name__ == "__main__":
main()
# test_global.py
n = 10 ** 7
mod = 10 ** 9 + 7
x = 0
for i in range(n):
x += i
x %= mod
Results:
python3 test_local.py 1.03s user 0.02s system 91% cpu 1.139 total
python3 test_global.py 1.92s user 0.01s system 98% cpu 1.956 total

pypy3 test_local.py 0.26s user 0.12s system 36% cpu 1.034 total
pypy3 test_global.py 0.13s user 0.03s system 97% cpu 0.161 total

Env:
CPython3 (3.8.2), PyPy3 (7.3.0)

为什么在 PyPy3 中 test_local.py 比 test_global.py 慢,尽管在 CPython 中结果相反?

更新
按照 Armin Rigo 的回答,我在下面尝试了另一个代码。
它工作得更快,同时将大部分部分保留在 main() 中。
#  test_global_constant.py
MOD = 10 ** 9 + 7


def main():
n = 10 ** 7
x = 0
for i in range(n):
x += i
x %= MOD


if __name__ == "__main__":
main()
Results:
python3 test_global_constant.py 1.08s user 0.01s system 99% cpu 1.099 total

pypy3 test_global_constant.py 0.12s user 0.03s system 95% cpu 0.164 total

最佳答案

答案可能在“%”运算符中。 PyPy 有一个 JIT,它一次查看一个循环(包括该循环完成的所有调用,如果有的话)。在代码的第一个版本中,循环是使用“x %= mod”编译的,其中“mod”的值不知道是一个常量——它只是一个来自函数早期的值。它可能看起来不变,但并不完全:如果你使用一些调试钩子(Hook)运行程序,那么你可以想象在进入循环之前就已经改变了它的值——即在 JIT 启动之前。出于这个原因,JIT 不会针对局部变量进行优化。此外,这在某种程度上是罕见的情况:局部变量通常不是常数。

另一方面,在第二种情况下,“x %= mod”使用全局变量“mod”。全局变量更常见的是常量(例如,大多数全局变量实际上是函数或类或数值常量)。所以 PyPy 中的 JIT 包含支持它的特殊代码。全局变量在内部比局部变量更复杂:它们会记住是否已更改,只要没有更改,它们就会记录已生成的汇编程序的哪些部分,假设它们是常量。因此,只要您不更改“mod”,那么“x %= mod”将由 JIT 编译,假设“mod”恰好是常量 1000000007。

为什么会有所作为?因为常数的除法和取模被替换为使用乘法的巧妙代码,使用众所周知的技巧。 GCC 或任何好的 C 编译器也使用类似的技巧。如果您对细节感兴趣,用基于乘法的东西替换常数除法的代码在这里(UINT_MUL_HIGH 用无符号 64 位数字 x 和 y 执行“(x * y)>> 64”,这是一个单一的汇编程序操作说明):
https://foss.heptapod.net/pypy/pypy/blob/branch/default/rpython/jit/metainterp/optimizeopt/intdiv.py

关于python - 在本地命名空间中编写代码比在 PyPy3 中的全局中慢,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/61144206/

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