PyPy3中本地命名空间中的代码编写速度比全局命名空间慢

问题描述 投票:2回答:1

我使用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
python pypy
1个回答
1
投票

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

© www.soinside.com 2019 - 2024. All rights reserved.