缓存模运算结果为何未提升Python循环性能反而变慢?
性能反向下降的核心原因
1. 第一个循环存在短路判断,实际取模运算次数低于第二个循环
你认为第一个循环会重复执行取模运算,但实际上Python的逻辑运算符和分支判断自带短路优化:
- 第一个判断
if loop_number % 3 == 0 and loop_number % 5 == 0中,只要loop_number % 3 != 0,就会直接跳过后面的loop_number %5运算,不会执行 - 上层分支匹配成功后,后续的
elif分支会直接跳过,不会执行对应的取模运算
在FizzBuzz场景下,大部分整数都不满足模3/模5等于0的条件,平均下来单轮迭代的取模运算次数甚至低于你第二个循环固定执行的2次取模。
2. 额外的变量赋值、读写开销超过了取模节省的成本
CPython对小整数的取模运算做了高度优化,本身执行开销极低。而你第二个循环每轮迭代都要额外执行2次局部变量赋值、后续判断还要额外读取2次变量,这部分开销已经超过了提前计算取模节省的成本,反而拖慢了执行速度。
3. 测试用例存在逻辑偏差
仔细核对代码可发现,两个循环的elif判断顺序并不一致:
- 第一个循环先判断
模5==0,再判断模3==0 - 第二个循环先判断
模3==0,再判断模5==0
虽然不影响本次性能结论,但严格来说两个循环的逻辑并不完全等价,也会对执行次数产生轻微影响。
附格式化后的测试代码:
from timeit import default_timer as timer loop1_time = 0 loop2_time = 0 for i in range(101): start = timer() for loop_number in range(50): if loop_number % 3 == 0 and loop_number % 5 == 0: a = 1 # print('FizzBuzz {} ' .format(loop_number)) elif loop_number % 5 == 0: # print('Buzz {} '.format(loop_number)) b = 2 elif loop_number % 3 == 0: # print('Fizz {}' .format(loop_number)) c = 3 end = timer() loop1_time = loop1_time + (end - start) # print("First loop took " + str(end - start)) start = timer() for loop_number in range(50): answer_of_3 = loop_number % 3 answer_of_5 = loop_number % 5 if answer_of_3 == 0 and answer_of_5 == 0: # print('FizzBuzz {} ' .format(loop_number)) d = 1 elif answer_of_3 == 0: # print('Buzz {} '.format(loop_number)) e = 2 elif answer_of_5 == 0: # print('Fizz {}' .format(loop_number)) f = 3 end = timer() loop2_time = loop2_time + (end - start) # print("Second loop took " + str(end - start)) print("First loop on average took " + str(loop1_time / 101)) print("Second loop on average took " + str(loop2_time / 101))
内容的提问来源于stack exchange,提问作者Atiq
相关产品推荐
相关产品推荐

