设置与冻结集的性能

时间:2016-04-11 17:21:18

标签: python performance set frozenset

我正在修补Python的setfrozenset集合类型。

最初,我假设frozenset提供比set更好的查找性能,因为它是不可变的,因此可以利用存储项的结构。

然而,对于以下实验,情况似乎并非如此:

import random
import time
import sys

def main(n):
    numbers = []
    for _ in xrange(n):
        numbers.append(random.randint(0, sys.maxint))
    set_ = set(numbers)
    frozenset_ = frozenset(set_)

    start = time.time()
    for number in numbers:
        number in set_
    set_duration = time.time() - start

    start = time.time()
    for number in numbers:
        number in frozenset_
    frozenset_duration = time.time() - start

    print "set      : %.3f" % set_duration
    print "frozenset: %.3f" % frozenset_duration


if __name__ == "__main__":
    n = int(sys.argv[1])
    main(n)

我使用CPython和PyPy执行了这段代码,结果如下:

> pypy set.py 100000000
set      : 6.156
frozenset: 6.166

> python set.py 100000000
set      : 16.824
frozenset: 17.248

在CPython和PyPy中,frozenset的查找性能实际上似乎较慢。有人知道为什么会这样吗?我没有查看实现。

2 个答案:

答案 0 :(得分:57)

frozensetset实施主要是共享的; set只是添加了变异方法的frozenset,具有完全相同的哈希表实现。见Objects/setobject.c source file;顶级PyFrozenSet_Type definition份额与PySet_Type definition共享。

此处没有对冻结集进行优化,因为在测试成员资格时,无需计算 frozenset中的项目的哈希值。用于测试集合的项目仍然需要计算其哈希值,以便在集合哈希表中找到正确的插槽,以便您可以进行相等性测试。

因此,由于系统上运行的其他进程,您的计时结果可能已关闭;你测量了挂钟时间,并没有禁用Python垃圾收集,也没有反复测试同样的东西。

尝试使用timeit module运行测试,其中一个值来自numbers,另一个值不属于集合:

import random
import sys
import timeit

numbers = [random.randrange(sys.maxsize) for _ in range(10000)]
set_ = set(numbers)
fset = frozenset(numbers)
present = random.choice(numbers)
notpresent = -1
test = 'present in s; notpresent in s'

settime = timeit.timeit(
    test,
    'from __main__ import set_ as s, present, notpresent')
fsettime = timeit.timeit(
    test,
    'from __main__ import fset as s, present, notpresent')

print('set      : {:.3f} seconds'.format(settime))
print('frozenset: {:.3f} seconds'.format(fsettime))

这重复每次测试100万次并产生:

set      : 0.050 seconds
frozenset: 0.050 seconds

答案 1 :(得分:4)

两个不同数据类型的原因不是性能,而是功能。由于冻结集是不可变的,因此可以将其用作字典中的键。集不能用于此目的。