首页 文章

与Python 3.4相比,为什么Python 3.5中的str.translate要快得多?

提问于
浏览
110

我试图在Python 3.4中使用 text.translate() 从给定的字符串中删除不需要的字符 .

最小的代码是:

import sys 
s = 'abcde12345@#@$#%$'
mapper = dict.fromkeys(i for i in range(sys.maxunicode) if chr(i) in '@#$')
print(s.translate(mapper))

它按预期工作 . 但是,在Python 3.4和Python 3.5中执行相同的程序会产生很大的差异 .

计算时间的代码是

python3 -m timeit -s "import sys;s = 'abcde12345@#@$#%$'*1000 ; mapper = dict.fromkeys(i for i in range(sys.maxunicode) if chr(i) in '@#$'); "   "s.translate(mapper)"

Python 3.4程序需要 1.3ms 而Python 3.5中的相同程序只需 26.4μs .

与Python 3.4相比,Python 3.5有哪些改进使其更快?

1 回答

  • 145

    TL;DR - ISSUE 21118


    The long Story

    Josh Rosenberg发现 str.translate() 函数与 bytes.translate 相比非常慢,他提出issue,说明:

    在Python 3中,str.translate()通常是性能悲观,而不是优化 .

    为什么str.translate()慢?

    str.translate() 非常慢的主要原因是查找曾经在Python字典中 .

    maketrans 的使用使这个问题变得更糟 . 使用bytes的类似方法构建了一个包含256个项目的C数组来快速查找表 . 因此,使用更高级别的Python dict 会使Python 3.4中的 str.translate() 变得非常慢 .

    现在发生了什么?

    第一种方法是添加一个小补丁translate_writer,然而速度的提升并不令人满意 . 很快又测试了另一个补丁fast_translate,它产生了非常好的结果,加速率高达55% .

    从文件中可以看出主要的变化是Python字典查找被更改为C级查找 .

    现在的速度与 bytes 几乎相同

    unpatched           patched
    
    str.translate                   4.55125927699919    0.7898181750006188
    str.translate from bytes trans  1.8910855210015143  0.779950579000797
    

    这里的一个小注意事项是性能增强仅在ASCII字符串中很突出 .

    正如J.F.Sebastian在下面的comment中提到的,在3.5之前,翻译曾经以相同的方式用于ASCII和非ASCII情况 . 但是从3.5 ASCII情况下要快得多 .

    早期的ASCII与非ascii过去几乎相同,但是现在我们可以看到性能的巨大变化 .

    它可以是从71.6μs到2.33μs的改进,如answer所示 .

    以下代码演示了这一点

    python3.5 -m timeit -s "text = 'mJssissippi'*100; d=dict(J='i')" "text.translate(d)"
    100000 loops, best of 3: 2.3 usec per loop
    python3.5 -m timeit -s "text = 'm\U0001F602ssissippi'*100; d={'\U0001F602': 'i'}" "text.translate(d)"
    10000 loops, best of 3: 117 usec per loop
    
    python3 -m timeit -s "text = 'm\U0001F602ssissippi'*100; d={'\U0001F602': 'i'}" "text.translate(d)"
    10000 loops, best of 3: 91.2 usec per loop
    python3 -m timeit -s "text = 'mJssissippi'*100; d=dict(J='i')" "text.translate(d)"
    10000 loops, best of 3: 101 usec per loop
    

    制表结果:

    Python 3.4    Python 3.5  
    Ascii     91.2          2.3 
    Unicode   101           117
    

相关问题