Python是否会自动将*2替换为<&书信电报;1.
我看到一些建议(例如),你不应该用移位运算符手动替换乘法,因为编译器必须自动执行,移位运算符会降低可读性。我编写了一个简单的测试来检查这一点:Python是否会自动将*2替换为<&书信电报;1.,python,python-3.x,cpython,python-internals,Python,Python 3.x,Cpython,Python Internals,我看到一些建议(例如),你不应该用移位运算符手动替换乘法,因为编译器必须自动执行,移位运算符会降低可读性。我编写了一个简单的测试来检查这一点: import numpy as np import time array1 = np.random.randint(size=10 ** 6, low=0, high=10 ** 5) array2 = np.zeros((10 ** 6,), dtype=np.int) total = 0.0 for i in range(100): st
import numpy as np
import time
array1 = np.random.randint(size=10 ** 6, low=0, high=10 ** 5)
array2 = np.zeros((10 ** 6,), dtype=np.int)
total = 0.0
for i in range(100):
start = time.clock()
for j in range(len(array2)):
array2[j] = array1[j] * 2
total += time.clock() - start
print("*2 time = " + str(round(total / 10, 5)) + " ms")
total = 0.0
for i in range(100):
start = time.clock()
for j in range(len(array2)):
array2[j] = array1[j] << 1
total += time.clock() - start
print("<< 1 time = " + str(round(total / 10, 5)) + " ms")
total = 0.0
for i in range(100):
start = time.clock()
for j in range(len(array2)):
array2[j] = array1[j] // 2
total += time.clock() - start
print("//2 time = " + str(round(total / 10, 5)) + " ms")
total = 0.0
for i in range(100):
start = time.clock()
for j in range(len(array2)):
array2[j] = array1[j] >> 1
total += time.clock() - start
print(">> 1 time = " + str(round(total / 10, 5)) + " ms")
怎么了?我的测试方法错了吗?时间测量错误吗?或者Python不执行这样的优化(如果是,我应该害怕吗)?我在Win 8.1 x64上使用了cPython 3.4.2 x64。此优化不会发生在字节码级别:
>>> import dis
>>> dis.dis(lambda x: x*2)
1 0 LOAD_FAST 0 (x)
3 LOAD_CONST 1 (2)
6 BINARY_MULTIPLY
7 RETURN_VALUE
>>> dis.dis(lambda x: x<<1)
1 0 LOAD_FAST 0 (x)
3 LOAD_CONST 1 (1)
6 BINARY_LSHIFT
7 RETURN_VALUE
导入dis
>>>dis.dis(λx:x*2)
1 0快速加载0(x)
3负载常数1(2)
6二进制乘法
7返回值
>>>dis.dis(lambda x:x此优化不会发生在字节码级别:
>>> import dis
>>> dis.dis(lambda x: x*2)
1 0 LOAD_FAST 0 (x)
3 LOAD_CONST 1 (2)
6 BINARY_MULTIPLY
7 RETURN_VALUE
>>> dis.dis(lambda x: x<<1)
1 0 LOAD_FAST 0 (x)
3 LOAD_CONST 1 (1)
6 BINARY_LSHIFT
7 RETURN_VALUE
导入dis
>>>dis.dis(λx:x*2)
1 0快速加载0(x)
3负载常数1(2)
6二进制乘法
7返回值
>>>dis.dis(lambda x:x使用(查看函数的字节码等价物)和(比使用time
手动计时更可靠)可以让您更好地了解内部情况。测试脚本:
def multiply(x):
return x * 2
def l_shift(x):
return x << 1
def divide(x):
return x // 2
def r_shift(x):
return x >> 1
if __name__ == '__main__':
import dis
import timeit
methods = (multiply, l_shift, divide, r_shift)
setup = 'from __main__ import {}'.format(
', '.join(method.__name__ for method in methods),
)
for method in methods:
print method.__name__
dis.dis(method)
print timeit.timeit(
'for x in range(10): {}(x)'.format(method.__name__),
setup=setup,
)
print
显然,Python没有用等价的位移位替换乘法/除法运算(例如,BINARY\u loor\u DIVIDE
没有被BINARY\u RSHIFT
替换),尽管看起来这样的优化可以提高性能。至于为什么位移动更快,请参见程序员。使用(查看与函数等效的字节码)和(比尝试手动使用时间进行计时更稳健)可以让您更好地了解内部情况。测试脚本:
def multiply(x):
return x * 2
def l_shift(x):
return x << 1
def divide(x):
return x // 2
def r_shift(x):
return x >> 1
if __name__ == '__main__':
import dis
import timeit
methods = (multiply, l_shift, divide, r_shift)
setup = 'from __main__ import {}'.format(
', '.join(method.__name__ for method in methods),
)
for method in methods:
print method.__name__
dis.dis(method)
print timeit.timeit(
'for x in range(10): {}(x)'.format(method.__name__),
setup=setup,
)
print
显然,Python没有用等价的位移位替换乘法/除法运算(例如,BINARY\u loor\u DIVIDE
没有被BINARY\u RSHIFT
替换),尽管看起来这样的优化可以提高性能。至于为什么位移动更快,请参见程序员。只有在非常有限的情况下,CPython才能实现这些优化。原因是CPython是一种被回避的类型化语言
给定代码片段x*2
,这可能意味着非常不同的事情,取决于x
的值。如果x
是一个整数,那么它确实具有与x相同的含义,只有在非常有限的情况下,CPython才能实现这些优化。原因是CPython是一种被回避的类型化语言
给定代码片段x*2
,根据x
的值,这可能意味着非常不同的事情。如果x
是一个整数,那么它确实具有与x相同的含义,您可以使用它来查看字节码,并获得更精确的计时。“我看到一些建议,不应该用移位运算符手动替换乘法,因为编译器必须自动执行,移位运算符会降低可读性。"-您在哪里看到这些建议?例如,想知道为什么在运行100次时要除以10。您在Unix上吗?Python是字节码解释的,字节码是源代码的表示形式,不应进行优化。优化可能发生在运行时。例如,在创建LLVM-IR时,LLVM不会创建此移位操作。当所有的东西都进入CPU并创建真正的指令时,这就是为什么你看到这些优化,例如C和C++编译器和JIT,而不是CPython。你可以用来查看字节码,并获得更精确的时序。“我看到一些建议,不应该用移位运算符手动替换乘法,因为编译器必须自动执行,移位运算符会降低可读性。"-您在哪里看到这些建议?例如,想知道为什么在运行100次时要除以10。您在Unix上吗?Python是字节码解释的,字节码是源代码的表示形式,不应进行优化。优化可能发生在运行时。例如,在创建LLVM-IR时,LLVM不会创建此移位操作。当所有的东西都进入CPU,并创建真正的指令时,这就是为什么你看到这些优化,例如C和C++编译器和JIT,而不是CPython。也许你可以更详细地解释这是什么。也许你可以更详细地解释一下这是什么。
In [3]: import dis
In [4]: def f():
...: return 2 * 2
...:
In [5]: dis.dis(f)
2 0 LOAD_CONST 2 (4)
3 RETURN_VALUE