>>> timeit.timeit(stmt="a*1.0/b",setup="a,b=3,2",number=100)
4.669614510532938e-05
>>> timeit.timeit(stmt="float(a)/b",setup="a,b=3,2",number=100)
7.18402232422477e-05
上記から、単純に を使用するa*1.0/b
方が を使用するよりもはるかに高速であることがわかりますfloat(a)
。これは、Python で関数を呼び出すには非常にコストがかかるためです。そうは言っても、次のようなことができます:
a,b=float(3),2
print a/b
そして、次のベンチマークがあります。
>>> timeit.timeit(stmt="a/b",setup="a,b=float(3),2",number=100)
2.5144078108496615e-05
これは、呼び出しがfloat()
1 回だけであり、それが の割り当てにあるためですa
。これにより、1.0*a
を考慮する必要がなくなり、はるかに高速な結果が得られます。
モジュールを使用してこれをさらに分解するdis
と、これに対する実際の呼び出しがループで表示されます。
分割時に浮きます
def floatmethod():
a,b=3,2
while True:
print float(a)/b
除算時のフロート dis results
dis.dis(floatmethod)
2 0 LOAD_CONST 3 ((3, 2))
3 UNPACK_SEQUENCE 2
6 STORE_FAST 0 (a)
9 STORE_FAST 1 (b)
3 12 SETUP_LOOP 25 (to 40)
>> 15 LOAD_GLOBAL 0 (True)
18 POP_JUMP_IF_FALSE 39
4 21 LOAD_GLOBAL 1 (float)
24 LOAD_FAST 0 (a)
27 CALL_FUNCTION 1
30 LOAD_FAST 1 (b)
33 BINARY_DIVIDE
34 PRINT_ITEM
35 PRINT_NEWLINE
36 JUMP_ABSOLUTE 15
>> 39 POP_BLOCK
>> 40 LOAD_CONST 0 (None)
43 RETURN_VALUE
速度低下の理由
このメソッドが非常に遅い理由は、最初に を取得し、次に( )LOAD_GLOBAL: float
の値を取得してから( ) を呼び出す必要があるためです。次に、最後に除算 ( ) を実行します。これらはすべて、ループ中に何度も実行されます。a
LOAD_FAST: a
float(a)
CALL_FUNCTION
BINARY_DIVIDE
浮動小数点割り当て
def initfloatmethod():
a,b=float(3),2
while True:
print a/b
float 割り当て dis 結果
dis.dis(initfloatmethod)
2 0 LOAD_GLOBAL 0 (float)
3 LOAD_CONST 1 (3)
6 CALL_FUNCTION 1
9 LOAD_CONST 2 (2)
12 ROT_TWO
13 STORE_FAST 0 (a)
16 STORE_FAST 1 (b)
3 19 SETUP_LOOP 19 (to 41)
>> 22 LOAD_GLOBAL 1 (True)
25 POP_JUMP_IF_FALSE 40
4 28 LOAD_FAST 0 (a)
31 LOAD_FAST 1 (b)
34 BINARY_DIVIDE
35 PRINT_ITEM
36 PRINT_NEWLINE
37 JUMP_ABSOLUTE 22
>> 40 POP_BLOCK
>> 41 LOAD_CONST 0 (None)
44 RETURN_VALUE
高速化の理由
除算が実行される行では、float 関数を呼び出す必要がなくなり、除算をすぐに実行できることがわかります。ループ内ではなく、割り当て時にLOAD_GLOBAL: float
呼び出して 1 回呼び出すだけです。CALL_FUNCTION
これは、通話に直接スキップできることを意味しBINARY_DIVIDE
ます。
このベンチマークに使用される統計:
Python 2.7.3 (default, Apr 10 2012, 23:31:26) [MSC v.1500 32 bit (Intel)] on win32