我找到了2个无分支函数,它们在python中找到两个数字的最大值,并将它们与if语句和内置max函数进行比较。我认为无分支函数或内置函数是最快的,但最快的是if语句函数。有人知道这是为什么吗?下面是函数:
if语句(25000次2.16秒):
def max1(a, b):
if a > b:
return a
return b
内置(4.69秒25000次操作):
def max2(a, b):
return max(a, b)
无分支1(运行25000次4.12秒):
def max3(a, b):
return (a > b) * a + (a <= b) * b
无分支2(25000次操作5.34秒):
def max4(a, b):
diff = a - b
return a - (diff & diff >> 31)
关于分支与无分支代码的期望适用于低级语言,如汇编和c。在低级语言中,无分支代码可以更快,因为它可以防止因分支预测错误而导致的减速。(注意:这意味着无分支代码可以更快,但不一定。)
Python是高级语言。假设您正在使用CPython解释器:对于您执行的每个字节码指令,解释器必须根据操作码的类型以及通常的许多其他内容进行分支。例如,即使是简单的<
操作符,也需要一个分支来检查<
操作码,另一个分支来检查对象的类是否实现了__lt__
方法,更多的分支来检查右侧的值是否为要执行的比较的有效类型,可能还有其他几个分支。即使你所谓的"无枝";由于这些原因,代码实际上会导致很多分支。
由于Python是如此高级,与单个机器代码指令相比,每个字节码指令实际上要做相当多的工作。所以像这样的简单代码的性能主要取决于需要解释多少字节码指令:
- 您的
max1
函数必须进行三次局部变量加载,比较,条件跳转和返回。六。 - 你的
max2
函数做两个局部变量的加载,一个全局变量的加载(引用内置的max
),也使一个函数调用;这需要传递参数,与其他字节码指令相比,成本相对较高。最重要的是,内置函数本身必须做与您自己的max1
函数相同的工作,所以难怪max2
更慢。 - 您的
max3
函数进行六次局部变量加载,两次比较,两次乘法,一次加法和一次返回。这是12条指令,所以我们应该期望它的时间是max1
的两倍。 - 同样,
max4
对局部变量进行了5次加载,一次存储到局部变量,一次加载常量,两次减法,一次位移,一次按位"one_answers",一次返回。又是12条指令。
也就是说,如果我们直接将max1
与内置函数max
进行比较,而不是将具有额外函数调用的max2
进行比较,则max1
函数仍然比内置max
快一点。这可能是因为内置的max
接受可变数量的参数,这可能涉及到构建一个参数元组,并且内置的max
函数也有一个分支来检查它是否被单个可迭代参数调用(例如max([3, 1, 4, 2])
),并以不同的方式处理这种情况;你的max1
函数不会做这些事情。
Python代码没有经过机器优化。你几乎不可能得到任何"无分支"。解析代码中的代码优化。
无分支代码有时更快,如果它有效地做更少的工作,或者硬件因此能够更好地进行分支预测。
函数调用是有成本的,所以如果函数内部的代码太琐碎,函数调用的成本就相对较高。
有一个缺失的控制情况:只需调用循环中的内置max函数并进行比较(就像max2一样,但没有函数调用开销)。很可能内置max是在C中实现的,并且已经针对您的硬件进行了优化。