web-dev-qa-db-ja.com

Trueの場合が1の場合よりも遅いのはなぜですか?

Pythonでif Trueif 1より遅いのはなぜですか? if Trueif 1よりも速くすべきではありませんか?

私はtimeitモジュールを学ぼうとしていました。基本から始めて、私はこれらを試しました:

>>> def test1():
...     if True:
...         return 1
...     else:
...         return 0

>>> print timeit("test1()", setup = "from __main__ import test1")
0.193144083023


>>> def test2():
...     if 1:
...         return 1
...     else:
...         return 0

>>> print timeit("test2()", setup = "from __main__ import test2")
0.162086009979


>>> def test3():
...     if True:
...             return True
...     else:
...             return False

>>> print timeit("test3()", setup = "from __main__ import test3")
0.214574098587

>>> def test4():
...     if 1:
...             return True
...     else:
...             return False

>>> print timeit("test4()", setup = "from __main__ import test4")
0.160849094391

私はこれらのことに混乱しています:

  1. この質問 のSylvain Defresne氏からの回答によると、最初にすべてが暗黙的にboolに変換され、次にチェックされます。では、なぜif Trueif 1よりも遅いのでしょうか。
  2. returnの値だけが異なるのに、test3test1より遅いのはなぜですか?
  3. 質問2と同様ですが、test4test2よりも少し速いのはなぜですか?

注:私はtimeitを3回実行し、結果の平均を取り、コードとともにここに時間を投稿しました。

この質問は、マイクロベンチマークの実行方法(この例では実行しましたが、基本的すぎることも理解しています)とは関係ありませんが、「True」変数のチェックが定数よりも遅いのはなぜですか。

32
thiruvenkadam

TrueFalsePython 2 のキーワードではありません。

それらは実行時に解決する必要があります。これは Python で変更されました

Python 3:で同じテスト

>>> timeit.timeit('test1()',setup="from __main__ import test1", number=10000000)
2.806439919999889
>>> timeit.timeit('test2()',setup="from __main__ import test2", number=10000000)
2.801301520000038
>>> timeit.timeit('test3()',setup="from __main__ import test3", number=10000000)
2.7952816800000164
>>> timeit.timeit('test4()',setup="from __main__ import test4", number=10000000)
2.7862537199999906

時間誤差は1%であり、これは許容範囲です。

29
Kabie

バイトコードの逆アセンブルは違いを明らかにします。

>>> dis.dis(test1)
  2           0 LOAD_GLOBAL              0 (True)
              3 JUMP_IF_FALSE            5 (to 11)
              6 POP_TOP             

  3           7 LOAD_CONST               1 (1)
             10 RETURN_VALUE        
        >>   11 POP_TOP             

  5          12 LOAD_CONST               2 (0)
             15 RETURN_VALUE        
             16 LOAD_CONST               0 (None)
             19 RETURN_VALUE        

Kabieが述べたように、TrueFalseはPython 2。のグローバルです。それらにアクセスするために多くのものが進行中です。

>>> dis.dis(test2)
  3           0 LOAD_CONST               1 (1)
              3 RETURN_VALUE        

Pythonコンパイラは、1を常に「真実の」式として認識し、冗長な状態を最適化することができました。

>>> dis.dis(test3)
  2           0 LOAD_GLOBAL              0 (True)
              3 JUMP_IF_FALSE            5 (to 11)
              6 POP_TOP             

  3           7 LOAD_GLOBAL              0 (True)
             10 RETURN_VALUE        
        >>   11 POP_TOP             

  5          12 LOAD_GLOBAL              1 (False)
             15 RETURN_VALUE        
             16 LOAD_CONST               0 (None)
             19 RETURN_VALUE        

test1とほぼ同じですが、もう1つLOAD_GLOBALがあります。

>>> dis.dis(test4)
  3           0 LOAD_GLOBAL              0 (True)
              3 RETURN_VALUE        

test2を参照してください。ただし、LOAD_GLOBALLOAD_CONSTよりも少しコストがかかります。

18
rkhayrov