Python が遅いのは、一般的な理由です。「GIL (グローバル インタプリタ ロック) であるため」、「コンパイル言語ではなくインタープリタ言語であるため」、「動的型付け言語であるため」。
推奨コース: Java チュートリアル 。
パフォーマンスに最も大きな影響を与える理由はどれですか?
「それは GIL だからです」
現代のコンピューターの CPU には複数のコアがあり、場合によっては複数のプロセッサーが搭載されています。すべてのコンピューティング能力を活用するために、オペレーティング システムはスレッドと呼ばれる基礎構造を定義し、プロセス (Chrome ブラウザなど) は複数のスレッドを生成して、スレッドを通じてシステム命令を実行できます。このようにして、プロセスが大量の CPU を使用する場合、コンピューティング負荷が複数のコア間で共有され、最終的にはほとんどのアプリケーションがより速くタスクを完了できるようになります。
この記事を書いている時点で、私の Chrome ブラウザでは 44 個のスレッドが開いています。さらに、POSIX ベースのオペレーティング システム (Mac OS や Linux など) のスレッド構造と API は、Windows オペレーティング システムのスレッド構造と API とは異なります。オペレーティング システムはスレッドのスケジューリングも担当します。
マルチスレッド プログラムを作成したことがない場合は、ロックの概念を理解する必要があります。シングルスレッドのプロセスとは異なり、マルチスレッド プログラミングでは、メモリ内の変数を変更するときに、複数のスレッドが同時に同じメモリ アドレスを変更またはアクセスしようとしないようにする必要があります。
CPython は変数の作成時にメモリを割り当て、カウンタを使用して変数への参照数をカウントします。この概念は「参照カウント」と呼ばれます。参照数が0の場合、変数をシステムから解放できます。こうすることで、(for ループのコンテキストなどで) 「一時的な」変数を作成しても、アプリケーションのメモリを使い果たすことがなくなります。
その後の問題は、変数が複数のスレッド間で共有されている場合、CPython は参照カウンターをロックする必要があることです。スレッドの実行を注意深く制御する「グローバル インタプリタ ロック」があります。スレッドがいくつあっても、インタプリタは一度に 1 つの操作しか実行できません。
これは Python アプリケーションのパフォーマンスにどのような影響を与えますか?
アプリケーションがシングルスレッド、シングルインタープリターの場合、速度には影響しません。 GIL を削除しても、コードのパフォーマンスには影響しません。
ただし、インタープリター (Python プロセス) を使用してスレッドによる同時実行性を実現する必要があり、スレッドが IO 集中型 (つまり、ネットワーク入出力やディスク入出力が大量にある場合) の場合は、 ) の場合、次のような GIL 競合が発生します:
Web アプリケーション (Django など) が WSGI を使用している場合、Web アプリケーションに送信される各リクエストは次のようになります。別の Python インタープリターによって実行されるため、リクエストごとにロックは 1 つだけになります。 Python インタープリターの起動は非常に遅いため、一部の WSGI 実装では、Python プロセスを長時間実行し続ける「デーモン モード」がサポートされています。
「インタープリタ型言語だから」
この理由はよく聞きますが、CPython が実際にどのように動作するかを単純化しすぎていることがわかりました。ターミナルで python myscript.py を記述すると、CPython は読み取り、字句解析、構文解析、コンパイル、解釈、実行を含む一連の長い操作を開始します。このプロセスの重要な点は、コンパイル段階で .pyc ファイルが生成され、バイトコードが __pycache__/ (Python 3 の場合) の下のファイルに書き込まれるか、ソース コードと同じディレクトリに書き込まれることです。 (Python 2)。これは、作成したスクリプトだけでなく、サードパーティのモジュールを含むインポートするすべてのコードにも当てはまります。
したがって、ほとんどの場合 (作成したコードが 1 回しか実行されない場合を除き)、Python はバイトコードを解釈してローカルで実行します。これを Java と C#.NET と比較してください。
Java はソース コードを「中間言語」にコンパイルし、Java 仮想マシンがバイトコードを読み取ってオンザフライでマシン コードにコンパイルします。 .NET CIL についても同様で、.NET の共通言語ランタイム (CLR) はジャストインタイム コンパイルを使用して、バイトコードをマシン コードにコンパイルします。
では、どちらも仮想マシンと何らかのバイトコードを使用しているのに、パフォーマンス テストで Python が Java や C# よりもはるかに遅いのはなぜでしょうか? 1 つ目の理由は、.NET と Java がジャスト イン タイム (JIT) でコンパイルされることです。
ジャストインタイム コンパイル、つまり JIT (ジャストインタイム) では、コードを小さな部分 (フレーム) に分割するための中間言語が必要です。 Ahead of Time (AOT) とは、コンパイラーがソース コードを、実行前に CPU が理解できるコードに変換することを意味します。
JIT 自体は同じバイトコード シーケンスを実行するため、実行を高速化するわけではありません。ただし、JIT は実行時に最適化を行うことができます。優れた GIT オプティマイザーは、「ホット スポット」と呼ばれる、アプリケーションの最も実行される部分を見つけることができます。これらのバイトコードは最適化され、より効率的なコードに置き換えられます。
これは、アプリケーションが何かを繰り返し実行する場合、処理が大幅に高速になることを意味します。また、Java と C# はどちらも厳密に型指定された言語であるため、オプティマイザーはコードに関してより多くの仮定を行うことができることを忘れないでください。
「動的型付け言語であるため」
C、C、Java、C#、Go などの「静的型」言語では、変数を定義するときに変数の型を指定する必要があります。
動的型付け言語にも型の概念がありますが、変数の型は動的です。
a = 1 a = "foo"
この例では、Python は同じ名前と str 型を持つ 2 番目の変数を定義し、同時に a の最初のインスタンスによって占有されていたメモリを解放します。
静的型付け言語の設計目的は人々を苦しめることではなく、これが CPU の動作方法であるため、このように設計されています。操作が最終的に単純なバイナリ操作に変換される場合は、オブジェクトと型の両方を低レベルのデータ構造に変換する必要があります。
Python はこれらすべてをあなたのために行ってくれますが、あなたはそれを気にしたことがありませんし、気にする必要もありません。
型を定義する必要がないことが、Python が遅い理由ではありません。 Python の設計により、すべてを動的にすることができます。実行時にオブジェクト メソッドを置き換えたり、実行時に基礎となるシステム コールにパッチを適用したりできます。ほぼ何でも可能です。
この設計により、Python の最適化が困難になります。
では、Python の動的型付けによって Python は遅くなるでしょうか?
型の比較と変換にはコストがかかります。読み取り、書き込み、参照のたびに型
をチェックする動的型付け言語は、最適化することが困難です。 Python の代替手段の多くが非常に高速である理由は、パフォーマンスのために利便性が犠牲になっているためです。
たとえば、Cython (http://cython.org/) は、C の静的型と Python のメソッドを組み合わせてコード内の型を認識させ、それによってコードを最適化し、 84 倍のパフォーマンス向上
概要
Python が遅い主な理由は、そのダイナミクスと多様性にあります。さまざまな問題の解決に使用できますが、ほとんどの問題には、より適切に最適化された高速な解決策があります。
しかし、Python アプリケーションには、非同期の使用、パフォーマンス テスト ツールの理解、複数のインタープリターの使用など、多くの最適化手段もあります。
起動時間が重要ではなく、コードが JIT の利点を享受できるアプリケーションの場合は、PyPy の使用を検討できます。
パフォーマンスが重要なコード部分で、変数のほとんどが静的型である場合は、Cython の使用を検討してください。
以上がJava が Python より速いのはなぜですか?の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。