はい、ここでの公開を停止していましたが、マーケティングの観点からは公開を継続する方が良いと考えられます...継続します。
ここに最初に公開されたテキスト。
このテキストの目的は、Python 言語の同時実行性と並列処理を理解するために必要な基本概念を直接要約することです。このテーマについて最低限の知識を持っておくか、このテキストと他の情報源からの学習を組み合わせることをお勧めします。すべての参考文献は本文の最後にあります。
次のトピックについて説明します:
コンピューティングにおいて、プロセスは、実行中のアプリケーションのインスタンスです。コンピュータ上でブラウザなどのアプリケーションを開くと、そのアプリケーションは何らかのプロセスに関連付けられます。プロセスは次のもので構成されます:
次の画像は、フランシス・マチャドとルイス・マイアの本から抜粋したものです:
この情報はプログラムを実行するために必要です。
スレッドはプログラムのサブルーチンであり、オペレーティング システムが管理する実行の最小単位であり、プロセスのコンポーネントです。
仮想プロセスのさまざまなスレッドは同時に実行でき (これについてはすぐに説明します)、メモリなどのリソースを共有します。異なるプロセスはこれらのリソースを共有しません。
以下の画像は Wikipedia から引用したものです:
上の画像を解釈すると、プログラムはディスク (二次的な不揮発性メモリ) に保存されており、いくつかの命令が含まれており、1 つ以上のプロセスでインスタンス化 (開始) でき、これらのプロセスにはいくつかの関連スレッド。
これら 2 つの表現は、競争に関する議論で頻繁に登場し、ポルトガル語では I/O (入出力) と CPU (中央処理装置) について登場することがあります。
I/O バウンドと CPU バウンドについて話すときは、コンピューター上での操作の高速化を妨げる制限要因について話しています。これら 2 種類の操作は同じコードベースで見つけることができます。
CPU バウンド操作は CPU を集中的に使用するため、CPU がより強力であればより高速に実行されます。言い換えれば、クロック速度を 2 GHz から 4 GHz にすると、この操作はおそらくより速く実行されるでしょう。ここでは、多くの計算、計算を実行する操作について話しています。たとえば、円周率の計算方法など。
I/O バウンド操作は、ネットワーク速度と入出力デバイスの速度に依存します。 Web サーバーへのリクエストやディスクからのファイルの読み取りは、I/O バウンド操作です。
どちらのタイプの操作でも同時実行性を使用するとメリットが得られます。
GIL は グローバル インタプリタ ロックの略で、Python プロセスが同時に複数の Python 命令バイトコードを実行するのを防ぐことを目的としています。スレッドを実行するには、GIL を「取得」する必要があります。あるスレッドが GIL を保持している間、別のスレッドが同時に GIL を取得することはできません。これは、このコンテキストで複数のスレッドを使用できないという意味ではありません。
ここでは、Python のリファレンス実装を検討します。 CPython は Python の標準実装であり、言語の動作の参考として使用されます。 Jython や IronPython などの他の実装もあります。 GIL は CPython に存在しますが、つい最近、GIL をオプションにすることを提案する PEP (Python Enhancement Proposal) がありました。
GIL の考え方は、複数のスレッドが Python オブジェクトを同時に参照する必要がある場合に発生する可能性がある 競合状態 を防ぐことです。複数のスレッドが共有変数を変更する場合、その変数は予期しない状態になる可能性があります。マシュー・ファウラーの本から引用した画像:
上の画像では、2 つのスレッドが同時に参照カウントを増やそうとしていますが、カウントが 2 になるのではなく、どちらも 1 ずつ増えているため、最終結果は 1 になります (各スレッドは列です)。
コンピューティングにおける競合は、これら 2 つのタスクをまったく同時に実行する必要はなく、複数のタスクを処理するときに発生します。この件に関するロブ・パイクの有名なフレーズ:
競争とは、同時に多くのことに対処することを意味します。並列処理とは、多くのことを同時に実行することです。
次の仮定の状況について考えてください。ケーキを 2 つ作る場合は、オーブンを予熱することから始めて、その間に 1 つ目のケーキの生地を準備します。オーブンが適切な温度になったら、最初のケーキの生地をオーブンに入れ、ケーキがオーブン内で膨らむのを待っている間に、2 番目のケーキの生地を準備できます。競争の考え方は基本的に次のようなものです。タスクが完了するのを待っている間、アイドル状態になったり、スタックしたり、停止したりする必要はなく、切り替えを行ってタスクを変更することができます。
この文脈では、2 つのタイプのマルチタスクがあります:
以下の画像は、Python での同時実行性を要約するのに役立ちます:
並列処理とは、複数のタスクが同時に実行されることを意味します。言い換えれば、並列性は並行性 (複数のタスクを処理する) を意味しますが、同時性は並列性を意味しません (タスクは必ずしも同時に並行して実行されるわけではありません)。並列処理を可能にするには、複数の CPU コアが必要です。
Python では、たとえば、マルチプロセシング ライブラリを使用して並列処理が実現されます。この場合、それぞれが独自の GIL を持つ複数の Python プロセスが存在します。この画像は、Python での並列処理を説明するのに役立ちます:
Python で同時実行性と並列処理を実現するにはさまざまな方法があり、処理する操作のタイプ (I/O バウンドまたは CPU バウンド) に応じて、いくつかのライブラリを使用してコードを最適化できます。 asyncio は、async と await を使用して同時実行を実現するための ライブラリです。ドキュメントより:
Asyncio は、高性能ネットワークや Web サーバー、データベース接続ライブラリ、分散ジョブ キューなどを提供するいくつかの非同期 Python フレームワークの基盤として使用されます。
ご想像のとおり、このライブラリは、ネットワーク待機時間やディスクへの書き込みなどがある I/O バウンド タスクの最適化に適しています。 CPU バウンド操作では待機はなく、CPU の計算速度のみに依存します。
Python のスレッド ライブラリを使用すると、複数のスレッドを操作できます。ただし、依然として 1 つの CPU コアと 1 つの Python プロセスを処理しており、これはオペレーティング システムが実行するプリエンプティブ マルチタスクのケースであることに注意してください。私たちにとってタスクの切り替えです。このライブラリは、I/O バウンド操作の最適化にも役立ちます。
スレッド化については、Real Python Web サイトにいくつかの重要なポイントが記載されています。
あるタスクがいつ停止し、別のタスクが開始されるかはオペレーティング システムによって制御されるため、スレッド間で共有されるデータはすべて保護、つまりスレッド セーフする必要があります。残念ながら、requests.Session() はスレッドセーフではありません。データの内容とその使用方法に応じて、データ アクセスをスレッドセーフにするための戦略がいくつかあります。その 1 つは、スレッドセーフ データ構造を Python キュー モジュールのキューとして使用することです。
キューのドキュメントはここにあります。
Python ドキュメントのマルチプロセッシング ライブラリについて:
multiprocessing は、スレッド モジュールと同様の API を使用してプロセスの生成をサポートするパッケージです。マルチプロセッシング パッケージはローカルとリモートの両方の同時実行性を提供し、スレッドの代わりにサブプロセスを使用することで GIL を効果的にバイパスします。そのため、マルチプロセッシング モジュールを使用すると、プログラマは 1 台のマシン上の複数のプロセッサを利用できるようになります。
異なる CPU コアで複数のプロセスを実行することは、GIL を無効にすることを意味するのではなく、各プロセスが独自の GIL を持つことを意味することに注意してください。複数の CPU コアを利用し、使用可能な複数のコア間で重い CPU ワークロードを共有することにより、ライブラリは CPU バウンドにより適しています。
出典:
ファウラー、マシュー。 asyncio による Python 同時実行。マニング出版物、2022 年。
マチャド、フランシス・ベレンジャー;マイア、ルイス・パウロ。オペレーティング システム アーキテクチャ: SOSIM シミュレータを使用した演習と ENADE の質問が含まれます。リオデジャネイロ: LTC、2013.
Wikipedia のスレッド (コンピューティング)
本物の Python による同時実行で Python プログラムを高速化
以上がPython の同時実行性と並列性の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。