为什么比使用`.update`更快地从连接列表创建集合?

时间:2015-09-09 15:23:20

标签: python performance optimization set

在尝试回答What is the preferred way to compose a set from multiple lists in Python时,我做了一些性能分析,得出了一个令人惊讶的结论。

使用

python -m timeit -s '
import itertools
import random
n=1000000
random.seed(0)
A = [random.randrange(1<<30) for _ in xrange(n)]
B = [random.randrange(1<<30) for _ in xrange(n)]
C = [random.randrange(1<<30) for _ in xrange(n)]'

对于设置,我定时了以下片段:

> $TIMEIT 'set(A+B+C)'
10 loops, best of 3: 872 msec per loop

> $TIMEIT 's = set(A); s.update(B); s.update(C)'
10 loops, best of 3: 930 msec per loop

> $TIMEIT 's = set(itertools.chain(A,B,C))'
10 loops, best of 3: 941 msec per loop

令我惊讶的是,set(A+B+C)最快的,尽管它创建了一个包含3000000个元素的中间列表。 .updateitertools.chain都较慢,即使它们都没有复制任何列表。

这里发生了什么?

编辑:在第二台机器(OS X 10.10.5,Python 2.7.10,2.5GHz Core i7)上,我运行了以下脚本(向前和向后运行测试以避免排序效果):

SETUP='import itertools
import random
n=1000000
random.seed(0)
A = [random.randrange(1<<30) for _ in xrange(n)]
B = [random.randrange(1<<30) for _ in xrange(n)]
C = [random.randrange(1<<30) for _ in xrange(n)]'

python -m timeit -s "$SETUP" 'set(A+B+C)'
python -m timeit -s "$SETUP" 's = set(A); s.update(B); s.update(C)'
python -m timeit -s "$SETUP" 's = set(itertools.chain(A,B,C))'

python -m timeit -s "$SETUP" 's = set(itertools.chain(A,B,C))'
python -m timeit -s "$SETUP" 's = set(A); s.update(B); s.update(C)'
python -m timeit -s "$SETUP" 'set(A+B+C)'

并获得以下结果:

10 loops, best of 3: 579 msec per loop
10 loops, best of 3: 726 msec per loop
10 loops, best of 3: 775 msec per loop
10 loops, best of 3: 761 msec per loop
10 loops, best of 3: 737 msec per loop
10 loops, best of 3: 555 msec per loop

现在set(A+B+C) 显然更快,而且结果非常稳定 - 很难将其归结为单纯的测量误差。重复运行此脚本会产生类似的结果。

0 个答案:

没有答案