设为首页 收藏本站
查看: 755|回复: 0

[经验分享] Python while 1 和 while True 速度比较

[复制链接]

尚未签到

发表于 2015-12-2 07:45:20 | 显示全部楼层 |阅读模式


References
  http://legacy.python.org/dev/peps/pep-0285/
http://stackoverflow.com/questions/3815359/while-1-vs-for-whiletrue-why-is-there-a-difference


  本文内容遵从CC3.0版权协议,转载请注明:转自Pythoner
  本文链接地址:Python天坑系列(一):while 1比while True更快?
  
  

1. 前提

  1.1 bool是int的子类
  根据PEP285中Review部分第6条所述,bool类是从int类继承而来的,这样可以极大的简化实现(C代码中调用PyInt_Check()的地方仍将继续工作)。

  1.2 Python2中True/False不是关键字,但Python3中是
  



我们可以导入keyword模块,来查看关键字:



>>> import keyword
>>> keyword.kwlist
['and', 'as', 'assert', 'break', 'class', 'continue', 'def', 'del', 'elif', 'else', 'except', 'exec', 'finally', 'for', 'from', 'global', 'if', 'import', 'in', 'is', 'lambda', 'not', 'or', 'pass', 'print', 'raise', 'return', 'try', 'while', 'with', 'yield']
  而在Python3中,关键字中添加了True/False/None。
  由于Python2中True/False不是关键字,因此我们可以对其进行任意的赋值:



>>> (1==1) == True
True
>>> True = "abc"
>>> (1==1) == True
False
  
  

2. True + True = 2
  由于bool是继承自int的子类,因此为了保证向下兼容性,在进行算术运算中,True/False会被当作int值来执行。
  



>>> True + True
2
>>> True - True
0
>>> True * True
1
>>> (True + True) > 1
True
>>> True + 5
6
>>> False + 1
1
>>> 1 / False
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
ZeroDivisionError: integer division or modulo by zero
  
  3. While 1比While True快?
  首先来看一个比较while 1和while True循环的脚本,两个函数中,除了1和True的区别之外,其他地方完全相同。



import timeit
def while_one():
i = 0
while 1:
i += 1
if i == 10000000:
break
def while_true():
i = 0
while True:
i += 1
if i == 10000000:
break
if __name__ == '__main__':
wone = timeit.timeit(while_one,"from __main__ import while_one",number=3)
wt = timeit.timeit(while_true,"from __main__ import while_true",number=3)
print "while_one: %s\nwhile_true: %s" % (wone,wt)
  
  执行结果:
  while_one: 0.937821149826
while_true: 1.39164209366
  可以看出wihle 1的执行时间约为while True的2/3   
  那么,这是为什么呢?
  其实这就是前提中提到的关键字的问题。由于Python2中,True/False不是关键字,因此我们可以对其进行任意的赋值,这就导致程序在每次循环时都需要对True/False的值进行检查;而对于1,则被程序进行了优化,而后不会再进行检查。
  
  我们可以通过dis模块来查看while_one和while_true的字节码,下面的程序是对刚才的程序进行了一定的简化后的版本



import dis
def while_one():
while 1:
pass
def while_true():
while True:
pass
if __name__ == "__main__":
print "while_one\n"
dis.dis(while_one)
print "while_true\n"
dis.dis(while_true)
  
  执行的结果是:





while_one
6           0 SETUP_LOOP               3 (to 6)
7     >>    3 JUMP_ABSOLUTE            3
>>    6 LOAD_CONST               0 (None)
9 RETURN_VALUE        
while_true
10           0 SETUP_LOOP              10 (to 13)
>>    3 LOAD_GLOBAL              0 (True)
6 POP_JUMP_IF_FALSE       12
11           9 JUMP_ABSOLUTE            3
>>   12 POP_BLOCK           
>>   13 LOAD_CONST               0 (None)
16 RETURN_VALUE  

  
  可以看出,正如上面所讲到的,在while True的时候,字节码中多出了几行语句,正是这几行语句进行了True值的检查。
  而在Python3中,由于True/False已经是关键字了,不允许进行重新赋值,因此,其执行结果与while 1不再有区别(好吧,我这没有Python3的环境,就不去验证了,网上有人验证过了)。但是由于Python2的使用十分广泛,因此大家不得不注意这个可能会降低性能的地方。



4. if x == True: 还是 if x:
  在PEP285中,还提到了这两种写法的比较。PEP285中认为,==具有传递性,a==b, b==c会被化简为a==c。也就是说,如果选择前一种写法的话,6和7在if语句中都应该被认为是真值,那么就会造成6==True==7,被化简为6==7的问题,因此后一种写法才是正确的。
  现在,让我们偏个题,假设x就是True,那么程序的执行效率又如何呢?



import timeit
def if_x_equal_true():
x = True
if x == True:
pass
def if_x():
x = True
if x:
pass
if __name__ == "__main__":
if1 = timeit.timeit(if_x_equal_true,"from __main__ import if_x_equal_true",number = 1000000)
if2 = timeit.timeit(if_x,"from __main__ import if_x",number = 1000000)
print "if_x_equal_true: %s\nif_x: %s" % (if1,if2)
  执行结果:
  if_x_equal_true: 0.127066850662
if_x: 0.0872008800507



让我们再来看看字节码(程序未作修改,dis的使用方式同上,因此不再给出程序):
  



if_x_equal_true
7           0 LOAD_GLOBAL              0 (True)
3 STORE_FAST               0 (x)
8           6 SETUP_LOOP              16 (to 25)
>>    9 LOAD_FAST                0 (x)
12 LOAD_GLOBAL              0 (True)
15 COMPARE_OP               2 (==)
18 POP_JUMP_IF_FALSE       24
9          21 JUMP_ABSOLUTE            9
>>   24 POP_BLOCK           
>>   25 LOAD_CONST               0 (None)
28 RETURN_VALUE        
if_x
12           0 LOAD_GLOBAL              0 (True)
3 STORE_FAST               0 (x)
13           6 SETUP_LOOP              10 (to 19)
>>    9 LOAD_FAST                0 (x)
12 POP_JUMP_IF_FALSE       18
14          15 JUMP_ABSOLUTE            9
>>   18 POP_BLOCK           
>>   19 LOAD_CONST               0 (None)
22 RETURN_VALUE        

  
  
  
  可以清晰的看到第9行比第14行,多出了检查True值和进行比较的操作。
  也就是说,不论从遵循PEP的规范,还是执行效率,或者程序的简洁性来说,我们都应该使用if x:,而不是if x == True:来进行比较。同理,那些if x is not None:之类的语句也应当被简化为if x:(如果要比较的是非值,而不必须是None的话)。




运维网声明 1、欢迎大家加入本站运维交流群:群②:261659950 群⑤:202807635 群⑦870801961 群⑧679858003
2、本站所有主题由该帖子作者发表,该帖子作者与运维网享有帖子相关版权
3、所有作品的著作权均归原作者享有,请您和我们一样尊重他人的著作权等合法权益。如果您对作品感到满意,请购买正版
4、禁止制作、复制、发布和传播具有反动、淫秽、色情、暴力、凶杀等内容的信息,一经发现立即删除。若您因此触犯法律,一切后果自负,我们对此不承担任何责任
5、所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其内容的准确性、可靠性、正当性、安全性、合法性等负责,亦不承担任何法律责任
6、所有作品仅供您个人学习、研究或欣赏,不得用于商业或者其他用途,否则,一切后果均由您自己承担,我们对此不承担任何法律责任
7、如涉及侵犯版权等问题,请您及时通知我们,我们将立即采取措施予以解决
8、联系人Email:admin@iyunv.com 网址:www.yunweiku.com

所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其承担任何法律责任,如涉及侵犯版权等问题,请您及时通知我们,我们将立即处理,联系人Email:kefu@iyunv.com,QQ:1061981298 本贴地址:https://www.yunweiku.com/thread-146039-1-1.html 上篇帖子: python学习笔记---前言 下篇帖子: python学习之---匿名函数,返回函数,偏函数
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

扫码加入运维网微信交流群X

扫码加入运维网微信交流群

扫描二维码加入运维网微信交流群,最新一手资源尽在官方微信交流群!快快加入我们吧...

扫描微信二维码查看详情

客服E-mail:kefu@iyunv.com 客服QQ:1061981298


QQ群⑦:运维网交流群⑦ QQ群⑧:运维网交流群⑧ k8s群:运维网kubernetes交流群


提醒:禁止发布任何违反国家法律、法规的言论与图片等内容;本站内容均来自个人观点与网络等信息,非本站认同之观点.


本站大部分资源是网友从网上搜集分享而来,其版权均归原作者及其网站所有,我们尊重他人的合法权益,如有内容侵犯您的合法权益,请及时与我们联系进行核实删除!



合作伙伴: 青云cloud

快速回复 返回顶部 返回列表