最近、マルチスレッド、マルチプロセス、コルーチンなど、Pythonの並列開発技術を勉強し始めました。インターネット上の情報を少しずつ整理していき、今日はグリーンレット関連の情報を整理しました。
同時処理の技術的背景
並列処理は現在大きな注目を集めています。特にマルチコアとマルチプロセッサの時代では、多くの場合、並列コンピューティングによってシステムのスループットが大幅に向上するため、Lisp のような古代言語が採用されてきました。それ以来、関数型プログラミングはますます人気が高まっています。 Pythonで並列処理を行うためのライブラリ「greenlet」を紹介します。 Pythonにはスタックレスと呼ばれる非常に有名なライブラリがあり、これは主にタスクレットと呼ばれるマイクロスレッドを使用します。グリーンレットとスタックレスの最大の違いは、非常に軽量であることです。十分ではありません。グリーンレットではスレッドの切り替えを自分で処理する必要があるということです。つまり、どのグリーンレットを今実行するか、どのグリーンレットを再度実行するかを指定する必要があります。
Greenlet 実装メカニズム
以前は、Python を使用して Web プログラムを開発し、常に fastcgi モードを使用していました。その際、各プロセスで複数のスレッドを開始してリクエストを処理していました。ここでの問題の 1 つは、各リクエストの応答時間を確実に短縮する必要があることです。短い場合は、リクエストが遅すぎる場合のみ、スレッドがリクエストに応答できないため、サーバーはサービスを拒否します。通常、サービスはオンラインになるときにパフォーマンスがテストされるため、通常の状況ではそれほど問題はありません。ただし、すべてのシナリオをテストすることは不可能です。一度表示されると、ユーザーは応答せずに長時間待機することになり、その後、Python のグリーンレットに切り替えました。その実装メカニズムを簡単に理解しました。
各グリーンレットはヒープ内の単なる Python オブジェクト (PyGreenlet) であるため、1 つのプロセスに対して数百万、場合によっては数千万のグリーンレットを作成しても問題ありません。
各グリーンレットは実際には関数であり、この関数の実行時にコンテキストが保存されます。同じプロセス内のすべてのグリーンレットは、オペレーティング システムによって割り当てられた共通のユーザー スタックを共有します。同時に、競合しないスタック データを持つグリーンレットのみがこのグローバル スタックを使用できます。実行されるグリーンレットの stack_stop がスタック内にあるグリーンレットと重複する場合、グリーンレットはスタックの最下部と最上部を保存します。この場合、これらの重複するグリーンレットのスタック データを一時的にヒープに保存する必要があります。保存された場所は stack_copy と stack_saved によって記録され、スタック内の stack_stop と stack_start の場所をヒープからコピーして戻すことができます。そうしないと、スタック データが破棄されます。そのため、アプリケーションによって作成されたグリーンレットは、データをヒープに、またはヒープからスタックに継続的にコピーすることによって並行性を実現します。IO にコルーチンを使用すると非常に便利です。快適なタイプのアプリケーションです。
以下は、greenlet の単純なスタックスペースモデル (greenlet.c より)
グリーンレットのスタック レイアウト:
| ^^^ |
| 古いデータ |
| |
stack_stop 。 |_______________|
。 | |
。 |グリーンレット データ |
。 | スタック内 |
。 * |_______________| 。 。 _____________ stack_copy + stack_saved
。 | | | |
。 | データ | |グリーンレットデータ|
。 | 無関係 | | 保存しました |
。 | に | | ヒープ内 |
stack_start 。 | これ | 。 。 |_____________| stack_copy
| グリーンレット |
| |
| 新しいデータ |
| vvv |
次は第 1 段简单の greenlet 代コードです。
def test1():
12を印刷
gr2.switch()
印刷34
def test2():
印刷56
gr1.switch()
印刷 78
gr1 = greenlet(test1)
gr2 = greenlet(test2)
gr1.switch()
現在認識されているプログラムは、通常、サポートされているプログラムで提供されています。現在、サポートされているプログラムには、Python、lua、go、erlang、scala、Rust が含まれていることがわかっています。プロセスは、オペレーティング システムによって切り替えられるのではなく、プログラムのコードによって切り替えられます。つまり、切り替えはプログラムによって制御され、これには、オンライン プログラムによる安全性の問題がありません。
すべてのプロセスはプロセス全体のコンテキストを共有しており、このようなトランザクション間の交換も非常に便利です。2 番目の方式 (I/O 多重化) と比較して、1 つのフローを複数の管理イベントに分割するのではなく、プログラム記述を使用するプログラムの完全性が向上します。この欠点は、ポリコアを利用できないことである可能性がありますが、これはプロセス + プロセスによって解決できます。
プロセスは、処理およびパフォーマンスの向上に使用でき、また、Python のプロセスを実現するために使用できます。 greenlet も pycon china2011 による処理収量の 1 つであり、特にステータス マシンの処理に使用される、より利用可能な方法であると考えられています。このブロックはすでに実質的に完了しており、次のポンプ時間は引き続き続きます。
总结一下:1) マルチコアを利用したマルチプロセスが可能ですが、プロセス間の通信が遅くなり、また、プロセス数の増加によりパフォーマンスが低下し、プロセス切り替えのコストが高くなります。低い。
2) I/O マルチルートは、プロセスの切り替えを行わずに複数の中間フローを処理し、パフォーマンスが高く、さらにフロー間で情報を共有します。イベント処理は 1 つの小さなブロックに分割されており、プログラムはより複雑であることを理解してください。
3) スレッドはプロセス内で実行され、オペレーティング システムによってスケジュールされます。さらに、プロセスの仮想アドレス空間を共有するため、スレッド間での情報の共有が簡単になります。ただし、スレッドの安全性の問題により、スレッドの学習曲線が急峻になり、エラーが発生しやすくなります。
4) コルーチンはプログラミング言語によって提供され、プログラマーの制御下で切り替えられるため、スレッドの安全性の問題はなく、ステート マシン、同時リクエストなどの処理に使用できます。ただし、マルチコアを活用することはできません。
上記の 4 つのソリューションは組み合わせて使用できます。私はプロセス + コルーチン モデルについてより楽観的です。