在下面我時間10_000_000檢查 if10是否在{0, ..., 9}.
在第一個檢查中我使用了一個中間變數,在第二個中我使用了一個文字。
import timeit
x = 10
s = set(range(x))
number = 10 ** 7
stmt = f'my_set = {s} ; {x} in my_set'
print(f'eval "{stmt}"')
print(timeit.timeit(stmt=stmt, number=number))
stmt = f'{x} in {s}'
print(f'eval "{stmt}"')
print(timeit.timeit(stmt=stmt, number=number))
輸出:
eval "my_set = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9} ; 10 in my_set"
1.2576093
eval "10 in {0, 1, 2, 3, 4, 5, 6, 7, 8, 9}"
0.20336140000000036
為什么第二個更快(大約是 5-6 倍)?Python 是否執行了一些運行時優化,例如,是否對文字進行包含檢查?或者可能是由于垃圾收集(因為它是一個文字 python 垃圾在使用后立即收集它)?
uj5u.com熱心網友回復:
您并沒有真正測驗相同的兩件事。在第一個測驗中,除了成員資格測驗之外,您還要計時兩個分配和查找。
In [1]: import dis
...: x = 10
...: s = set(range(x))
In [2]: dis.dis("x in s")
1 0 LOAD_NAME 0 (x)
2 LOAD_NAME 1 (s)
4 CONTAINS_OP 0
6 RETURN_VALUE
In [3]: dis.dis("my_set = s; x in my_set")
1 0 LOAD_NAME 0 (s)
2 STORE_NAME 1 (my_set)
4 LOAD_NAME 2 (x)
6 LOAD_NAME 1 (my_set)
8 CONTAINS_OP 0
10 POP_TOP
12 LOAD_CONST 0 (None)
14 RETURN_VALUE
# By request
In [4]: dis.dis("s = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9}; 10 in s")
1 0 BUILD_SET 0
2 LOAD_CONST 0 (frozenset({0, 1, 2, 3, 4, 5, 6, 7, 8, 9}))
4 SET_UPDATE 1
6 STORE_NAME 0 (s)
8 LOAD_CONST 1 (10)
10 LOAD_NAME 0 (s)
12 CONTAINS_OP 0
14 POP_TOP
16 LOAD_CONST 2 (None)
18 RETURN_VALUE
使用文字的實際區別在于x in s后者需要在全域變數中執行查找,即區別在于LOAD_NAMEvs LOAD_CONST:
In [5]: dis.dis("10 in {0, 1, 2, 3, 4, 5, 6, 7, 8, 9}")
1 0 LOAD_CONST 0 (10)
2 LOAD_CONST 1 (frozenset({0, 1, 2, 3, 4, 5, 6, 7, 8, 9}))
4 CONTAINS_OP 0
6 RETURN_VALUE
次數:
In [6]: %timeit x in s
28.5 ns ± 0.792 ns per loop (mean ± std. dev. of 7 runs, 10000000 loops each)
In [7]: %timeit 10 in {0, 1, 2, 3, 4, 5, 6, 7, 8, 9}
20.3 ns ± 0.384 ns per loop (mean ± std. dev. of 7 runs, 10000000 loops each)
轉載請註明出處,本文鏈接:https://www.uj5u.com/gongcheng/333550.html
上一篇:尾遞回函式的性能
下一篇:Mysql查詢優化
