web-dev-qa-db-ja.com

whileループを使用するよりもPythonのrange()でループするのが速いのはなぜですか?

先日、私はいくつかのPythonベンチマークを行っていて、何か面白いことに出会いました。以下は、ほぼ同じことを行う2つのループです。ループ1の実行には、ループ2の約2倍の時間がかかります。

ループ1:

int i = 0
while i < 100000000:
  i += 1

ループ2:

for n in range(0,100000000):
  pass

なぜ最初のループはそれほど遅いのですか?些細な例であることは知っていますが、興味をそそられました。同じ方法で変数をインクリメントするよりも効率的にするrange()関数について特別なものはありますか?

69
A. Dorton

pythonバイトコードの逆アセンブリを参照してください。より具体的なアイデアを得ることができます。

whileループを使用します。

1           0 LOAD_CONST               0 (0)
            3 STORE_NAME               0 (i)

2           6 SETUP_LOOP              28 (to 37)
      >>    9 LOAD_NAME                0 (i)              # <-
           12 LOAD_CONST               1 (100000000)      # <-
           15 COMPARE_OP               0 (<)              # <-
           18 JUMP_IF_FALSE           14 (to 35)          # <-
           21 POP_TOP                                     # <-

3          22 LOAD_NAME                0 (i)              # <-
           25 LOAD_CONST               2 (1)              # <-
           28 INPLACE_ADD                                 # <-
           29 STORE_NAME               0 (i)              # <-
           32 JUMP_ABSOLUTE            9                  # <-
      >>   35 POP_TOP
           36 POP_BLOCK

ループ本体には10個のop

使用範囲:

1           0 SETUP_LOOP              23 (to 26)
            3 LOAD_NAME                0 (range)
            6 LOAD_CONST               0 (0)
            9 LOAD_CONST               1 (100000000)
           12 CALL_FUNCTION            2
           15 GET_ITER
      >>   16 FOR_ITER                 6 (to 25)        # <-
           19 STORE_NAME               1 (n)            # <-

2          22 JUMP_ABSOLUTE           16                # <-
      >>   25 POP_BLOCK
      >>   26 LOAD_CONST               2 (None)
           29 RETURN_VALUE

ループ本体には3つのop

Cコードを実行する時間は、インタープリターよりもはるかに短く、無視できます。

142
kcwu

range()はCで実装されていますが、_i += 1_は解釈されます。

xrange()を使用すると、多数の場合でも高速化できます。 Python 3.0で始まるrange()は以前のxrange()と同じです。

31
Georg Schölly

Whileループでは多くのオブジェクトの作成と破棄が行われていることを言わなければなりません。

i += 1

以下と同じです:

i = i + 1

ただし、Python intsは不変であるため、既存のオブジェクトを変更するのではなく、新しい値で新しいオブジェクトを作成します。基本的には次のとおりです。

i = new int(i + 1)   # Using C++ or Java-ish syntax

ガベージコレクターには、大量のクリーンアップも必要です。 「オブジェクトの作成は高価です」。

12
Peter

インタープリターでCで記述されたコードをより頻繁に実行しているためです。つまり、i + = 1はPythonであるため、(比較的)遅いですが、range(0、...)はC呼び出しの1つであり、forループはほとんどCでも実行されます。

3
John Montgomery

Pythonの組み込みメソッド呼び出しのほとんどは、Cコードとして実行されます。解釈する必要があるコードは非常に低速です。メモリ効率と実行速度の点で、違いは非常に大きいです。 python internalsは極端に最適化されており、これらの最適化を利用するのが最善です。

1
ohdeargod