在python中将布尔值赋予变量和将字符串赋予变量之间是否存在明显的速度差异?

时间:2019-12-12 15:21:10

标签: python performance

我目前正在开发一个关注性能的python项目,因为我的CPU始终使用其90%至98%的计算能力。

所以我在考虑如何更改代码以使其更快,并注意到我有一个字符串变量,该变量始终接收两个值之一:

state = "ok" 
state = "notOk"

由于它只有2个值,因此我很难将其更改为类似boolean的值:

isStateOk = True
isStateOk = False

这样做有意义吗?将字符串归因于变量并将布尔值归因于变量的速度是否有很大差异,或根本没有差异?

我还应该提到,我在代码中使用了30个如果比较这个变量,那么也许比较速度会有所帮助吗?

if (state == "ok) # Original comparison
if (isStateOk)    # New comparison

2 个答案:

答案 0 :(得分:1)

那不会使用90-98%的CPU来修复程序,但是从技术上来说,使用布尔值会更好。

您也可以使用is instead of ==

isStateOk = True

if isStateOk is True:
    # Do stuff

编辑: 没关系,在https://hg.python.org/cpython/rev/01a7e66525c2/中,他们已经使== True被Python解释器转换为引擎盖下的is True,因此以任何一种方式编写都没有性能差异。

虽然在这里使用布尔值是个好主意,因为布尔值的目的是表示正常/不正常状态,但不会带来任何明显的性能改进。

答案 1 :(得分:1)

如另一个答案所述,这种微优化可能无法修复代码。可能你应该看看更一般的东西(算法、数据类型/结构以及在 Python 中有效使用它们的方法,例如使用 map/filter/reduce/list comprehensions 而不是 for 循环等)。

但是,关于您问题的血腥细节,请尝试运行以下测试:

import time

def measure_time(a_function, times):
    start = time.perf_counter()
    #for i in range(times):
    a_function(times)
    end = time.perf_counter()
    print ("{0:40} {1}".format( a_function.__name__, end - start ) )

def test_strings_eq_literal(n):
    stateOk = "ok"
    stateNotOK = "notOK"
    state = stateNotOK
    for i in range(n):
        state == "ok"

def test_strings_is_literal(n):
    stateOk = "ok"
    stateNotOk = "notOK"
    state = stateNotOk
    for i in range(n):
        state is "ok"  # careful with this - it works for simple, id-like strings only
    
def test_strings_eq(n):
    stateOk = "ok"
    stateNotOK = "notOK"
    state = stateNotOK
    for i in range(n):
        state == stateOk

def test_strings_is(n):
    stateOk = "ok"
    stateNotOk = "notOK"
    state = stateNotOk
    for i in range(n):
        state is stateOk  # careful with this - it works for simple, id-like strings only

def test_bool_eq_literal(n):
    stateOk    = True
    stateNotOk = False
    state      = stateNotOk
    for i in range(n):
        stateOk == True

def test_bool_is_literal(n):
    stateOk    = True
    stateNotOk = False
    state      = stateNotOk
    for i in range(n):
        state is True
        
def test_bool_eq(n):
    stateOk    = True
    stateNotOk = False
    state      = stateNotOk
    for i in range(n):
        stateOk == stateOk

def test_bool_is(n):
    stateOk    = True
    stateNotOk = False
    state      = stateNotOk
    for i in range(n):
        state is stateOk
        
n = 100000000
measure_time( test_strings_eq_literal, n )
measure_time( test_strings_is_literal, n )
measure_time( test_strings_eq, n )
measure_time( test_strings_is, n )
measure_time( test_bool_eq_literal, n )
measure_time( test_bool_is_literal, n )
measure_time( test_bool_eq, n )
measure_time( test_bool_is, n )

我得到:

test_strings_eq_literal                  3.6397838770062663
test_strings_is_literal                  2.9926898650010116
test_strings_eq                          3.7794520660536364
test_strings_is                          3.0217343979747966
test_bool_eq_literal                     3.4703008759533986
test_bool_is_literal                     2.836865450022742
test_bool_eq                             3.5056013059802353
test_bool_is                             2.847688327950891

什么表明您使用 is 而不是 == 获得最大收益(高达约 20%),即使使用一些字符串(但要小心 - is 仅适用于简单的/short id-like 字符串;你必须确定你在这里做什么;即使是解释器在其中一种情况下也会发出警告,所以最好不要这样做)。

相比之下,通过使用文字而不是变量似乎可以获得一点点(有点预期 - 必须在幕后额外完成一些取消引用层),但这并不值得关注。

在另一个答案中不太正确的地方(这实际上触发了我的回答)是布尔值和简单的类似 id 的字符串(并且只有这样!)都是 Python 中的单例对象,并且在性能上几乎没有区别像你这样的情况。但是,对于较长的字符串(带有空格等),情况不是 - 这样的字符串不能与 is 进行比较,并且将它们与 == 进行比较会比使用布尔值。

但如上所述 - 不如先看看程序中更一般/基本的东西。仅仅改变这一点并不能解决您的问题。