5

私の理解

C++ はマシン コードにコンパイルされ、実行されます。

Python はバイトコードにコンパイルされます

次に、このバイトコードが実行されます

この実行ステップには何が必要で、Cpython と PyPy ではどのように違うのでしょうか?

パフォーマンスの違いはどこで発生しますか? Python が動的に型付けされているという事実は、パフォーマンスの点でどこに影響しますか?

ありがとう!

4

1 に答える 1

8

C、C++、およびその他の静的にコンパイルされた言語は、ネイティブ マシン コードにコンパイルされます。つまり、コンピューターの CPU がそれらを直接実行できます。コンパイル後のコードは理解できないバイナリ データですが、次のような C コード フラグメントを想像することはできます。

int x = 10;
int y = x * 2;

次のような意味を持つ一連のバイナリ命令にコンパイルされます。

store 10 into memory address 200
multiply the contents of memory address 200 by 2, treating them as integers
store the result of the last instruction into memory address 300

コンパイラがメモリ アドレスを変数に割り当てxyコードに表示される場所。実際のマシン コードはこれよりも複雑で、英語のフレーズではなく、短いバイナリ コードワードにエンコードされていることに注意してください。しかし、それは非常に基本的な考え方です。x特に注意すべき点は、コンパイラがとが整数であることを知っていたため、整数乗算を使用することを認識していたことyです。CPU 自体は、メモリ アドレス 200 の内容の意味についてはまったく知りません。ビットについて知っているだけで、さまざまな方法でそれらをシャッフルするように指示できます。その 1 つが整数乗算です。

現在、Python はバイト コードにコンパイルされています。これらの問題について話しているとき、それは実際にはあまり興味深いことを意味しません. Python バイト コードは、マシン コードとは異なり、マシンで直接実行できる低レベルの操作をエンコードしません。実際、これは基本的に、Python ソース コードに記述したものとまったく同じ Python レベルの操作をエンコードするだけであり、CPU は Python バイト コードでは何もできません。Python インタープリターは、Python バイト コードでエンコードされた命令を実行するジョブを持つプログラムです。バイトコードのコンパイルが行うことは、インタープリターが、より簡単かつ迅速に操作できるコード形式で操作できるようにすることだけです。Python のソース コードを直接理解するために必要なすべての文字列処理を行う必要はありません。

ここで、動的型付けとパフォーマンスの違いが生まれます。C++ コンパイラは、x * 2これを CPU の単一の整数乗算命令にコンパイルできることを認識しています。

Python インタープリターは、乗算をサポートする組み込み型があるかどうか、カスタム乗算を実装するクラスであるかどうか、または乗算を実装しないが継承するクラスであるかどうかx * 2を確認するために、多くの手順を実行する必要があります。x他の何かから、または例外を作成する必要があるかどうか。が整数の場合、Python 整数を表すデータ構造からxマシンレベルの値を取得する手順があり、次に 1 つのマシンレベル命令で実際に CPU に整数乗算を実行させ、さらに命令をラップします。x結果は Python 整数データ構造に戻されます。

そのコードはすべて、多くのコンパイルされたマシン コード命令です (通常、CPython 上で実行されている PyPy の場合、それらは Python バイト コード命令です!)。Python インタープリター自体のコンパイル済みコード。Python のバイト コード コンパイラは、どのパスを使用するかを事前に判断し、Python ソース コードをそれらのマシン命令に変換できると考えるかもしれませんが、Python は動的に型付けされるため、それは不可能です。xそのコード行が最初に実行されるときは整数、次に実行されるときは文字列、その後はリストになる可能性があり、ある日はクラス インスタンスになることさえあります。したがって、Python は何が必要になるかを前もって知ることができないため、そのすべてのロジックを毎回実行する必要があります。したがって、Python ソース コードをネイティブ マシン コードにコンパイルするプログラムを作成したとしても、ほとんどの場合、Python インタープリターと基本的に同じことを行うマシン コードを生成する必要があります。

非常に簡単な概要として、これでほとんどの質問がカバーされます。また、あなたが興味を持っているものの詳細を実際に提供することなく、PyPy についても尋ねます。「なぜ PyPy は CPython よりも速いのですか (時々)」だと思います。基本的に、PyPy には JIT コンパイラがあります。これは、プログラムの実行中にコードをコンパイルする点を除いて、C++ コンパイラに少し似ています。xこれにより、Pythonが整数、浮動小数点数、リスト、またはその他のいずれかを認識できないという問題を (場合によっては) 回避できます。コードのビットを 1 回実行するのは、xたった 1 つのことです。そして、ほとんどの Python コードでxは、 は常に 1 つにすぎないか、場合によっては数少ないものの 1 つです。したがって、実行時にコードをコンパイルすることにより (どのコードが実際に頻繁に実行されるかを確認するのを待った後)、PyPy'x * 2単一の整数乗算マシン コード命令に変換されます。そのコード行をx整数で何百万回も実行すると、パフォーマンスが大幅に向上する可能性があります。ただし、次回xが文字列になる可能性はまだあるため、JIT にはフォールバック ロジックを含めて、Python が許可するすべての可能性を引き続き処理できるようにする必要があります。しかし、多くの可能性のうちどれが実際に頻繁に使用されているかを確認し、それらを最適化することで、速度を上げることができます。JIT は、実行時に何が起こっているかを確認するために待機できるため、C++ コンパイラではできないいくつかの最適化を行うことさえできますが、C++ は、実行時に何が起こっても機能するコードを発行する必要があります (ただし、型に基づいて仮定を行うことができます)。 、決して変わることはありません)。

于 2011-11-03T07:14:10.687 に答える