【发布时间】:2017-10-10 14:49:24
【问题描述】:
所以我正在编写一个函数,它接受一个元组作为参数,并对其进行一系列处理。看起来是这样的:
def swap(self, location):
if (location[0] < 0 or location[1] < 0 or
location[0] >= self.r or location[1] >= self.c):
return False
self.board[0][0] = self.board[location[0]][location[1]]
self.board[location[0]][location[1]] = 0
self.empty = (location[0],location[1])
我正在尝试使我的代码尽可能高效,因此由于我没有修改 location 的值,因此将变量加载到寄存器 (loc0 = location[0]; loc1 = location[1]) 以加快计算速度(零-循环读取)还是location在作为函数参数传入时已经被Python编译器加载到寄存器中?
编辑:我硬着头皮进行了一些测试。以下是此函数运行 1000 万次重复输入的结果(以秒为单位):"up", "down", "left", "right"(分别)
Code as is:
run#1: 19.39
run#2: 17.18
run#3: 16.85
run#4: 16.90
run#5: 16.74
run#6: 16.76
run#7: 16.94
Code after defining location[0] and location[1] in the beginning of the function:
run#1: 14.83
run#2: 14.79
run#3: 14.88
run#4: 15.033
run#5: 14.77
run#6: 14.94
run#7: 14.67
这意味着性能平均提高了 16%。对我来说绝对不是微不足道的。当然,这并不科学,因为我需要在更多环境中进行更多测试,输入更多,但对于我的简单用例来说已经足够了!
在Macbook Pro (Early 2015) 上使用 Python 2.7 测量的时间,Broadwell i5-5257U CPU(2c4t 最大 turbo 3.1GHz,持续 2.7GHz,3MB 三级缓存)。
IDE 是:PyCharm Edu 3.5.1 JRE:1.8.0_112-release-408-b6 x86_64 JVM:OpenJDK 64 位服务器虚拟机。
不幸的是,这是针对根据代码速度评分的课程。
【问题讨论】:
-
如果你这样做
loc0 = location[0],你是在设置一个变量,而不是一个“寄存器”。 -
您使用的是哪个 python JIT 编译器?如果您使用的是解释器,那么任何 Python 变量都不太可能存在于不同表达式之间的寄存器中。在 C 中,使用局部变量的一个好处是可能存在别名。 (例如,如果编译器认为修改 self.board[0][0] 可能也修改了 location[0],则将其读入本地将使编译器将其保存在寄存器中。) IDK 如果这是 Python 中的事情。 (我在这里是因为assembly 标签。)
-
@BrenBarn 是的,但是编译器通过为它们分配寄存器来优化经常使用的已定义变量。
-
@QuantumHoneybees:什么编译器? Python 不编译任何东西(无论如何也不编译为机器代码)。
-
它可能更快,因为它避免了
[]运算符和其他开销(请参阅您接受的 Bren 的答案),而不是因为它实际上将值保存在寄存器中。除非您是 JIT 编译,否则不值得专门使用一个寄存器来保存 Python 变量的值。为了使这更合理,解释器必须用 asm 编写,或者在 GNU C 中使用long last_used_variable asm("rdx")或其他东西。这毫无意义(我是作为一个经常查看 C 编译器 asm 输出的经验丰富的 asm 程序员/优化器说的。)
标签: python python-2.7 performance assembly