Python字符串连接速度

标签 python performance

我通过将字符串表示形式从 1 连接到一个大数字(在我的例子中是 20000000)来测试不同速度连接方法的速度。我正在测试的三种方法是:

import cProfile

count = 20000000

def profileWrapper(f):
    def wrapper(*args, **argv):
        pr = cProfile.Profile()
        pr.enable()
        string = f(*args, **argv)
        pr.create_stats()
        pr.print_stats()
        return string
    return wrapper

@profileWrapper
def naiveConcat():
    global count
    string = ''
    for i in xrange(count):
        string += `i`
    return string

@profileWrapper
def improvedConcat():
    global count
    string = []
    for i in xrange(count):
        string.append(`i`)
    return ''.join(string)

@profileWrapper
def fastestConcat():
    global count
    return ''.join([`i` for i in xrange(count)])

print 15 * "=", "naiveConcat", 15 * "="
naiveConcat()
print 15 * "=", "improvedConcat", 15 * "="
improvedConcat()
print 15 * "=", "fastestConcat", 15 * "="
fastestConcat()

我期待看到改进后的方法比原始方法更快,而且它不应该比最快的方法慢很多,但结果似乎不是那样:

=============== naiveConcat ===============
         3 function calls in 3.951 seconds

   Ordered by: standard name

   ncalls  tottime  percall  cumtime  percall filename:lineno(function)
        1    0.000    0.000    0.000    0.000 cProfile.py:90(create_stats)
        1    3.951    3.951    3.951    3.951 str_concat.py:18(naiveConcat)
        1    0.000    0.000    0.000    0.000 {method 'disable' of '_lsprof.Profiler' objects}


=============== improvedConcat ===============
         20000004 function calls in 6.990 seconds

   Ordered by: standard name

   ncalls  tottime  percall  cumtime  percall filename:lineno(function)
        1    0.000    0.000    0.000    0.000 cProfile.py:90(create_stats)
        1    5.196    5.196    6.990    6.990 str_concat.py:26(improvedConcat)
 20000000    1.322    0.000    1.322    0.000 {method 'append' of 'list' objects}
        1    0.000    0.000    0.000    0.000 {method 'disable' of '_lsprof.Profiler' objects}
        1    0.473    0.473    0.473    0.473 {method 'join' of 'str' objects}


=============== fastestConcat ===============
         4 function calls in 3.043 seconds

   Ordered by: standard name

   ncalls  tottime  percall  cumtime  percall filename:lineno(function)
        1    0.000    0.000    0.000    0.000 cProfile.py:90(create_stats)
        1    2.539    2.539    3.043    3.043 str_concat.py:34(fastestConcat)
        1    0.000    0.000    0.000    0.000 {method 'disable' of '_lsprof.Profiler' objects}
        1    0.504    0.504    0.504    0.504 {method 'join' of 'str' objects}

改进后的方法甚至比原始方法慢得多!

这没有意义,因为天真的方法正在创建新的绑定(bind)并在每次迭代时逐个字符地复制先前的字符串和连接的字符串,此方法应该采用 O(n^2),这应该慢得多比其他方法复杂度为 O(n)。

那么是什么让改进后的方法如此缓慢呢?我能想到的唯一原因是 append 方法,但根据 this article ,append方法需要O(1),所以肯定不是这个原因。那么在 improvedConcat() 中为什么需要这么长时间?谢谢。

最佳答案

improvedConcat 的 ncalls 列显示您进行了 20000004 次函数调用,而其他算法只有少数。函数调用在 Python 中并不便宜,所以尽量限制这些调用。为了演示,我按照您称为 nop 的模式做了一个新测试,它只调用一个空函数定义:

def foo():
    pass

@profileWrapper
def nop():
    for i in xrange(count):
        foo()
    return ''

我得到的计时结果与您的其他测试类似,而此 NOP(无操作)测试结果为

=============== nop ===============
20000003 function calls in 4.386 seconds

所以您有 4.4 秒的开销进行函数调用。

关于Python字符串连接速度,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/21588074/

相关文章:

php - MYSQL : SET value in an UPDATE query when all conditions of subquery are satisfied

python - 归并排序算法的误解

Python:创建具有多列表理解的字典

python - 带模块的可移植 Python 脚本

python - 如何使用 GCS compose 方法正确连接 CSV 文件?

c++ - 有没有更有效的方法来计算正模数?

python - 查找两个文件之间的差异非常慢

java - 比较两个列表并在 Java 中输出缺失和多余的元素

具有可执行依赖项的 Python C 扩展

performance - 查找具有给定 PR_SEARCH_KEY 的所有邮件