为什么Python的集合差异方法需要时间与空集?

时间:2016-09-07 19:55:12

标签: python performance set operators

这就是我的意思:

> python -m timeit "set().difference(xrange(0,10))"   
1000000 loops, best of 3: 0.624 usec per loop

> python -m timeit "set().difference(xrange(0,10**4))"
10000 loops, best of 3: 170 usec per loop

显然python遍历整个参数,即使事先知道结果是空集。这有什么好的理由吗?代码在python 2.7.6中运行。

(即使对于非空集,如果你发现你已经在迭代中途删除了所有第一组元素,那么立即停止是有道理的。)

3 个答案:

答案 0 :(得分:5)

  

这有什么好的理由吗?

之前没有出现空集的特殊路径。

  

即使对于非空集,如果您发现在迭代中途已经删除了所有第一组元素,那么立即停止是有道理的。

这是一个合理的优化请求。我已经制作了patch并很快就会申请。以下是应用补丁的新时间:

 $ py -m timeit -s "r = range(10 ** 4); s = set()" "s.difference(r)"
10000000 loops, best of 3: 0.104 usec per loop
 $ py -m timeit -s "r = set(range(10 ** 4)); s = set()" "s.difference(r)"
10000000 loops, best of 3: 0.105 usec per loop
 $ py -m timeit -s "r = range(10 ** 4); s = set()" "s.difference_update(r)"
10000000 loops, best of 3: 0.0659 usec per loop
 $ py -m timeit -s "r = set(range(10 ** 4)); s = set()" "s.difference_update(r)"
10000000 loops, best of 3: 0.0684 usec per loop

答案 1 :(得分:4)

IMO这是一个专业化问题,请考虑:

In [18]: r = range(10 ** 4)

In [19]: s = set(range(10 ** 4))

In [20]: %time set().difference(r)
CPU times: user 387 µs, sys: 0 ns, total: 387 µs
Wall time: 394 µs
Out[20]: set()

In [21]: %time set().difference(s)
CPU times: user 10 µs, sys: 8 µs, total: 18 µs
Wall time: 16.2 µs
Out[21]: set()

显然,差异是set - set的专门实施。

请注意,差异运算符要求右手参数为集合,而差异允许任何可迭代。

每个@wim实现位于https://github.com/python/cpython/blob/master/Objects/setobject.c#L1553-L1555

答案 2 :(得分:3)

当Python核心开发人员添加新功能时,首要任务是具有全面测试覆盖率的正确代码。这本身就很难。加速通常会在有人有想法和倾向的时候出现。我打开了跟踪器问题28071,总结了此处讨论的提案和反原因。我会在这里总结一下它的性格。

更新:已经为3.6.0b1添加了一个开始为空的集合的提前输出,大约需要一天。