Python Greenlet実装メカニズム

巴扎黑
巴扎黑オリジナル
2016-12-09 14:45:471229ブラウズ

最近、私は 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;

以下は、簡単な段落の greenlet コードです

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       |

声明:
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。