为什么在字典中查找要比Python中的两个if-tests快得多?

时间:2011-02-01 10:46:00

标签: python performance dictionary

我需要读取千兆字节的文本,所以我正在尝试优化我的代码。这样做时,我发现,对于我的问题,使用字典比if-tests更快。

check = {'R':'-', 'F':'+'}
seqs = ['R', 'F']*100

def check1():
    for entry in seqs:
        if entry == 'R':
            strand = '-'
        if entry == 'F':
            strand = '+'

def check2():
    for entry in seqs:
        strand = check[entry]

使用ipythong的%timeit我发现在字典中查找的速度比使用两个if-test快两倍:

In [63]: %timeit check1()
10000 loops, best of 3: 38.8 us per loop

In [64]: %timeit check2()
100000 loops, best of 3: 16.2 us per loop

由于if-tests是如此基本,我没想到性能差异。这是众所周知的吗?任何人都可以解释为什么会这样吗?

更新

我检查了上面的两个函数以及下面的check3()如何影响我实际代码的运行时间,并且对总时间没有影响。因此,在现实世界的例子中,要么字典中的提升不是那么高,其中'R'和'F'值需要不断地从文件中重新读取,或者这段代码不是我的瓶颈的一部分

无论如何,谢谢你的答案!

4 个答案:

答案 0 :(得分:7)

您实际上并未证明在字典中查找比两次if测试更快。您所展示的是,查找特定字典比这两个测试更快。

通常,字典查找需要几个步骤:从密钥生成哈希以找到潜在匹配,然后通过比较密钥来测试潜在匹配。如果存在哈希表冲突,有时可能需要进行多次比较。如果你有用户定义的键类,那么这两个步骤都可能很慢,它们通常对字符串很快,但在一个特殊情况下它们真的非常快,你已经遇到了这种情况。

您的词典使用的短字符串与编译时已知的标识符格式相匹配。 Python将有助于“实践”你的字符串'R'和'F'。由于您在测试中使用的字符串在编译时也是已知的,因此它们将是完全相同的实例。对字典查找的所有这些意味着,查找的专用版本用于仅具有字符串键的字典,哈希始终是预先计算的,并且通过比较地址来进行密钥比较(至少在成功时和您的它永远不会失败的两把钥匙。)

你的真实代码,我假设是从输入读取字符串,所以它不会有'R'的实习副本。这意味着它需要计算每行输入的哈希值。地址不匹配,因此必须为每个测试调用字符串比较函数。你仍然只对字符串键进行一些优化,至少它不必对可能不是字符串的对象进行通用比较。

if语句对对象类型一无所知,因此每次都会进行通用比较。

答案 1 :(得分:4)

与许多VM代码一样,它主要归结为所涉及的VM操作码数量。

您可以使用dis检查汇编的函数:

import dis
dis.dis(func)

在2.6.4中,对于每个比较和分支,check1需要大约15-20个操作码(取决于代码路径)。 check2只需7(在添加缺少的chedict字典后,全局声明)。

答案 2 :(得分:1)

字典在Python中进行了大量优化;查询是O(1) - 它只是一个哈希表查找,因此只是一个“操作” - 使用if测试序列(O(n))获得的操作数量的一半。

答案 3 :(得分:1)

这会揭示一些事情:

def check3():
    for entry in seqs:
        if entry == 'R':
            strand = '-'
        else:
            strand = '+'

它实际上比我计算机上的check2()快。