ホームページ >バックエンド開発 >Python チュートリアル >Python Greenlet実装メカニズム
最近、私は Python を使用して Web プログラムを開発しており、常に fastcgi モードを使用しています。このとき、各プロセスで複数のスレッドが開始され、リクエストを処理する必要があります。そうでない場合は、複数のリクエストが発生するだけで、スレッドがリクエストに応答できないため、サーバーがサービスを拒否します。そのため、通常の状況では大きな問題はありません。ただし、すべてのシナリオをテストすることは不可能です。一度発生すると、ユーザーは応答せずに長時間待たされるため、後で Python でコルーチンとグリーンレットに切り替えました。私は、その実装メカニズムを簡単に理解しています。
各グリーンレットはヒープ オブジェクト (PyGreenlet) 内の単なる Python であるため、プロセスごとに数百万、さらには数千万のグリーンレットを作成することは問題ありません。 greenlet は実際には関数であり、この関数の実行時にコンテキストを保存します。関数の場合、コンテキストはそのスタックです。同じプロセス内のすべてのグリーンレットは、オペレーティング システムによって割り当てられた共通のユーザー スタックを共有します。 - 競合するスタック データは、実行されるグリーンレットの stack_stop が現在スタック内にあるグリーンレットと重なる場合、スタックの最下部とスタック スタートを通じてスタックを同時に使用できます。これらの重複するグリーンレットのスタック データは、スタック内の stack_stop と stack_start の位置をリカバリ中にヒープからスタックにコピーできるように、stack_copy と stack_saved によって一時的にヒープに保存する必要があります。そうしないと、スタック データが破壊されます。そのため、アプリケーションによって作成されたグリーンレットは、常にデータをヒープにコピーするか、ヒープからスタックにコピーされます。IO タイプのアプリケーションでコルーチンを使用すると、非常に快適になります。
以下は、greenlet の単純なスタックスペースモデルです (greenlet.c より)
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;
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 |
。