CPython でスタック (1 つまたは複数のスタック フレーム) をプログラムで構築し、任意のコード ポイントで実行を開始することは可能ですか? 次のシナリオを想像してください。
ワークフロー エンジンへの呼び出しであるいくつかの構造 (分岐、待機/結合など) を使用して Python でワークフローをスクリプト化できるワークフロー エンジンがあります。
wait や join などのブロッキング呼び出しは、ある種の永続的なバッキング ストアを使用して、イベント ディスパッチ エンジンでリスナー条件を設定します。
エンジンで待機条件を呼び出し、後で通知される条件を待機するワークフロー スクリプトがあります。これにより、イベント ディスパッチ エンジンにリスナーが設定されます。
ワークフロー スクリプトの状態、関連するスタック フレーム (プログラム カウンター (または同等の状態) を含む) は、数日後または数か月後に待機状態が発生する可能性があるため、保持されます。
その間に、ワークフロー エンジンが停止され、再起動される可能性があります。つまり、ワークフロー スクリプトのコンテキストをプログラムで保存および再構築できる必要があります。
イベント ディスパッチ エンジンは、待機条件がピックアップするイベントを発生させます。
ワークフロー エンジンは、シリアル化された状態とスタックを読み取り、スタックを使用してスレッドを再構築します。次に、待機サービスが呼び出された時点で実行を継続します。
質問
これは、変更されていない Python インタープリターで実行できますか? さらに良いことに、この種のことをカバーする可能性のあるドキュメント、またはプログラムでスタック フレームを構築し、コード ブロックの途中で実行を開始するコードの例を誰かに教えてもらえますか?
編集:「変更されていない python インタープリター」を明確にするために、C API を使用してもかまいません (これを行うには PyThreadState に十分な情報がありますか?) が、Python インタープリターの内部を調べて、変更されたものを構築します。
更新:最初の調査から、実行コンテキストを取得できますPyThreadState_Get()
。これは、のスタック フレームへの参照を持つPyThreadState
(で定義された)のスレッド状態を返します。スタック フレームは、 で定義されている にtypedef された構造体に保持されます。 コードブロックの先頭からのオフセットとして表されるプログラムカウンターを持つフィールド(bobinceへの小道具)があります。pystate.h
frame
PyFrameObject
frameobject.h
PyFrameObject
f_lasti
これは、実際にコンパイルされたコード ブロックを保持している限り、必要な数のスタック フレームのローカルを再構築し、コードを再起動できることを意味するため、一種の朗報です。これは、変更された python インターペレタを作成しなくても理論的には可能であることを意味すると思いますが、コードはおそらく、インタープリタの特定のバージョンに厄介で緊密に結合される可能性があることを意味します。
残る問題は次の3つです。
トランザクション状態と 'saga' ロールバック。これは、O/R マッパーを構築するために使用するメタクラス ハッキングのようなものによっておそらく達成できます。私は一度プロトタイプを作成したので、これがどのように達成されるかについてかなりのアイデアを持っています.
トランザクション状態と任意のローカルを堅牢にシリアル化します。これは、読み取り
__locals__
(スタック フレームから利用可能) と、pickle への呼び出しをプログラムで作成することによって実現できます。ただし、ここに何があるのか わかりません。ワークフローのバージョン管理とアップグレード。システムはワークフロー ノードのシンボリック アンカーを提供していないため、これはやや複雑です。これを行うには、すべてのエントリ ポイントのオフセットを特定し、それらを新しいバージョンにマップする必要があります。おそらく手動で行うことは可能ですが、自動化するのは難しいと思います。この機能をサポートしたい場合、これがおそらく最大の障害になります。
更新 2: PyCodeObject
( code.h
) には addr ( f_lasti
)-> 行番号マッピングのリストがありPyCodeObject.co_lnotab
ます (ここで間違っている場合は訂正してください)。これは、ワークフローを新しいバージョンに更新するための移行プロセスを容易にするために使用される場合があります。これは、凍結された命令ポインターを新しいスクリプトの適切な場所にマップし、行番号に関して行うことができるためです。まだかなり面倒ですが、もう少し有望です。
更新 3:これに対する答えはStackless Python かもしれません。 タスクを一時停止してシリアル化できます。これがスタックでも機能するかどうかはわかりません。