最近、マルチスレッド、マルチプロセス、コルーチンなど、Pythonの並列開発技術を勉強し始めました。インターネット上の情報を少しずつ整理していき、今日はgreenlet関連の情報を整理しました。
多くの場合、特にマルチコアとマルチプロセッサの時代では、並列コンピューティングによってシステムのスループットが大幅に向上するため、並列処理は現在非常に重要です。 lisp のように人々はそれを再び取り上げるようになり、関数型プログラミングはますます人気が高まっています。 Pythonで並列処理を行うためのライブラリ「greenlet」を紹介します。 Pythonにはスタックレスと呼ばれる非常に有名なライブラリがあり、これは主にタスクレットと呼ばれるマイクロスレッドを使用します。グリーンレットとスタックレスの最大の違いは、非常に軽量であることです。十分ではありません。グリーンレットではスレッドの切り替えを自分で処理する必要があるということです。つまり、どのグリーンレットを今実行するか、どのグリーンレットを再度実行するかを指定する必要があります。
従来、Webプログラムの開発にはPythonが使用されており、リクエスト処理のために各プロセスで複数のスレッドが起動されていました。リクエストは特に短いことを保証する必要があります。そうでない場合、リクエストが遅すぎるとサーバーはサービスを拒否します。通常、サービスはオンラインになるときにパフォーマンスがテストされます。通常の状況ではそれほど問題はありませんが、すべてのシナリオで実行できるわけではありません。一度表示されると、ユーザーは応答せずに長時間待機することになり、後ですべてが使用できなくなります。 Python の下で Greenlet というコルーチンに変換されたので、その実装メカニズムを簡単に理解できました。
皆さん Greenlet はヒープ内にある単なる Python オブジェクト (PyGreenlet) なので、何百万、あるいは数十個作成しても問題ありません。
typedef struct _greenlet { PyObject_HEAD char* stack_start; char* stack_stop; char* stack_copy; intptr_t stack_saved; struct _greenlet* stack_prev; struct _greenlet* parent; PyObject* run_info; struct _frame* top_frame; int recursion_depth; PyObject* weakreflist; PyObject* exc_type; PyObject* exc_value; PyObject* exc_traceback; PyObject* dict; } PyGreenlet;
各グリーンレットは実際には関数であり、この関数の実行時にコンテキストが保存されます。同じプロセス内のすべてのグリーンレットは、割り当てられた共通のユーザー スタックを共有します。したがって、競合しないスタック データを持つグリーンレットのみがこのグローバル スタックを同時に使用できます。グリーンレットの stack_stop とスタックの先頭を保存するためにグリーンレットが使用されます。スタック内の stack_stop と stack_start の位置をコピーできるように、保存された位置は stack_copy と stack_saved によって記録されます。そうしないと、スタック データが破壊されます。したがって、アプリケーションによって作成されたグリーンレットは、継続的にデータをヒープにコピーしたり、ヒープからスタックにコピーしたりすることで、同時実行性を実現できます。 IO タイプのアプリケーションにコルーチンを使用するには
以下は、greenlet の単純なスタック スペース モデルです (greenlet.c より)
A PyGreenlet is a range of C stack addresses that must be saved and restored in such a way that the full range of the stack contains valid data when we switch to it. Stack layout for a greenlet: | ^^^ | | older data | | | stack_stop . |_______________| . | | . | greenlet data | . | in stack | . * |_______________| . . _____________ stack_copy + stack_saved . | | | | . | data | |greenlet data| . | unrelated | | saved | . | to | | in heap | stack_start . | this | . . |_____________| stack_copy | greenlet | | | | newer data | | vvv |
以下は、単純な greenlet コードです。プログラミング言語。現在、私が知っているコルーチン サポートを提供する言語には、Python、lua、go、erlang、scala、rust があります。コルーチンとスレッドの違いは、コルーチンはオペレーティング システムによって切り替えられるのではなく、
プログラマーコーディングによって切り替えられるということです。つまり、切り替えはプログラマーによって制御されるため、スレッドにはいわゆるセキュリティの問題はありません。 すべてのコルーチンはプロセス全体のコンテキストを共有するため、コルーチン間の交換も非常に便利です。
2 番目のソリューション (I/O 多重化) と比較すると、コルーチンを使用して作成されたプログラムは、完全なプロセスを複数のマネージド イベント ハンドラーに分割するのではなく、より直感的になります。コルーチンの欠点はマルチコアを利用できないことかもしれませんが、これはコルーチン + プロセスで解決できます。
コルーチンは、同時実行性を処理してパフォーマンスを向上させるために使用できます。また、ステート マシンを実装してプログラミングを簡素化するために使用することもできます。 2本目をさらに使います。私は昨年末に Python に出会い、Python のコルーチンの概念を知りました。その後、Greenlet もコルーチン ソリューションの 1 つであり、Python のコルーチンの概念を知りました。特にステートマシンの処理に使用できるソリューション。
現時点ではこの部分はほぼ完成していますので、後ほどまとめさせていただきます。
まとめると:
2) I/O多重化とは、プロセス内で複数の論理的なプロセスをプロセスを切り替えることなく処理することで、パフォーマンスが高く、プロセス間での情報共有が容易です。しかし、マルチコアの利点を活かすことができず、また、プログラムの流れがイベント処理によって細分化され、プログラムが複雑になり、わかりにくくなります。
3) スレッドはプロセス内で実行され、オペレーティング システムによってスケジュールされるため、スイッチング コストが低くなります。また、プロセスの仮想アドレス空間を共有するため、スレッド間での情報の共有が簡単になります。ただし、スレッドの安全性の問題により、スレッドの学習曲線が急峻になり、エラーが発生しやすくなります。
4) コルーチンはプログラミング言語によって提供され、プログラマーの制御下で切り替えられるため、スレッドの安全性の問題はなく、ステートマシン、同時リクエストなどの処理に使用できます。ただし、マルチコアを活用することはできません。
上記の 4 つのソリューションは一緒に使用できます。私はプロセス + コルーチン モデルについてより楽観的です
。以上がPython グリーンレットの使用法とその実装原理の分析の紹介の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。