键入 s vs 键入不键入 s 速度

key in s vs key not in s speed

我有这个代码:

s = set([5,6,7,8])

if key in s:
    return True

if key not in s:
    return False

在我看来,理论上它不应该在时间上有所不同,但我可能遗漏了一些内在的东西。

在处理时间或可读性方面,是否有任何理由比另一个更受欢迎?

也许这是一个例子:

"Premature optimization is the root of all evil"?


简短回答:不,没有区别。是的,可能是过早的优化。


好的,我运行这个测试:

import random
s = set([5,6,7,8])
for _ in range(5000000):
    s.add(random.randint(-100000,100000000))

def test_in():
    count = 0
    for _ in range(50000):
        if random.randint(-100000,100000000) in s:
            count += 1
    print(count)

def test_not_in():
    count = 0
    for _ in range(50000):
        if random.randint(-100000,100000000) not in s:
            count += 1
    print(count)

当我计时输出时:

%timeit test_in()
10 loops, best of 3: 83.4 ms per loop

%timeit test_not_in()
10 loops, best of 3: 78.7 ms per loop

但是,这个微小的差异似乎是对组件进行计数的症状。平均有 47500 "not ins" 但只有 2500 "ins"。如果我更改两个测试以通过,例如:

def test_in():
    for _ in range(50000):
        if random.randint(-100000,100000000) in s:
            pass

结果几乎相同

%timeit test_in()
10 loops, best of 3: 77.4 ms per loop

%timeit test_not_in()
10 loops, best of 3: 78.7 ms per loop

在这种情况下,我的直觉让我失望了。我原以为说 it is not in the set 可能会增加一些额外的处理时间。当我进一步考虑 hashmap 的作用时,显然情况并非如此。

您应该看不出有什么不同。集合中的查找时间是常数。您对条目进行哈希处理,然后在哈希图中查找它。所有keys同时check in,in vs not in应该是有可比性的。

运行 在与 timeit 的 ipython 会话中进行的简单性能测试证实了 g.d.d.c 的陈述。

def one(k, s):
    if k in s:
        return True     

def two(k, s):
    if k not in s:
        return False     

s = set(range(1, 100))

%timeit -r7 -n 10000000 one(50, s)
## 83.7 ns ± 0.874 ns per loop (mean ± std. dev. of 7 runs, 10000000 loops each)

%timeit -r7 -n 10000000 two(50, s)
## 86.1 ns ± 1.11 ns per loop (mean ± std. dev. of 7 runs, 10000000 loops each)

像这样的优化不会给你带来很多好处,正如评论中所指出的那样,实际上会降低你推出的速度 bugfixes/improvements/...由于可读性差。对于这种低级别的性能提升,我建议查看 Cython or Numba.