それをどのように呼ぶかわかりません。誰かがより良いタイトルを思いつくことができれば、私に知らせてください。この質問の名前を変更します。
これは実際の例ではありませんが、そのような状況の解決策が得られれば、より大きなプロジェクトで使用します. 以下で説明するようにそれをしなければならないと仮定してください。アイデアを変えることはできません。それに合う解決策を見つける必要があります。現時点では、元のプロジェクトの詳細を表示することは許可されていません。
考え:
では、YAPSY プラグインに基づいて、cron のようなものを作成していると仮定しましょう。プラグインをいくつかのディレクトリに保存したいのですが、たまにデーモンがそのディレクトリからすべてのプラグインを収集し、それらのメソッドを呼び出して、しばらくスリープ状態になります。これらのプラグインは、プラグインで使用される URL などのデータを保存するシングルトンにアクセスできる必要があります。また、このシングルトンを変更する同じプロセスで TCP サーバーを実行しているため、実行時の動作をカスタマイズできます。TCP サーバーにはシングルトンへの読み取り/書き込みアクセスが必要であり、プラグインには読み取り専用アクセスが必要です。多くのシングルトン (つまり、多くのクラスがシングルトンとして動作し、1 つのクラスのインスタンスが多くない) がプラグインで読み取り可能で、TCP サーバーで変更可能である可能性があります。プラグイン メソッドは、呼び出す直前に生成されたいくつかの値で呼び出されます。
質問:
プラグインへの読み取り専用アクセスを許可するにはどうすればよいですか? 完全な分離が必要なため、オブジェクトであるsingleton
fieldがある場合、 (like ) のフィールドもプラグインに対して読み取り専用にする必要があります。読み取り専用とは、プラグインがこれらのフィールドを変更できる必要があることを意味しますが、ランタイムの残りの部分には何の影響も与えないため、プラグイン メソッドが戻るとき、シングルトン (およびそのフィールド、およびそれらのフィールドなど) はプラグインメソッドを実行する前に、実際には読み取り専用ではありません。また、プラグインは並行して実行され、しばらくの間 GIL を解放します (IO 操作を行ったり、単に time.sleep() を使用したりする場合があります)。x
singleton.x
singleton.x.y
- 編集 -
ソリューションはマルチプラットフォームである必要があり、少なくとも Linux、Windows、および MacOS で動作する必要があります。
- /編集 -
アプローチ:
シングルトン メソッドのスタックを調べて、呼び出し元がプラグインかどうかを確認し、そうであれば、変更されたフィールドの元の値を保存することができます。次に、プラグイン メソッドを呼び出した後、プラグインを実行する前の状態にシングルトンを復元する関数 restore() を使用します。
マルチプロセッシングを使用して別のプロセスでプラグインメソッドを実行し、すべてのシングルトンをサブプロセスに渡すことを試みることができます (メタクラスを使用してすべてを追跡し、新しいプロセスで再構築するか、シングルトンをどこかに明示的に保存することで簡単に実行できます)。
ポイント(1)のように(元の値を復元して)同様のトリックを行うか、すべてのグローバルとローカルをディープコピーして、
globals()
プラグlocals()
インメソッドのコードで(文字列ではなく、私はそれが安全でないことを知っています)。dict
exec
上記のアプローチが機能しないのはなぜですか?
(1): 通常、スタック インスペクションは間違っています。この状況では、非常に間違っていると言えます。また、プラグインによって多くの変更が行われる場合、各呼び出しの後に変数を復元すると、非常にコストがかかる可能性があります。また、プラグイン メソッドは並行して実行される可能性があるため、GIL がリリースされるたびに元の値を復元し、GIL が取得されるたびにプラグイン全体の値を復元する必要があります。現時点ではできませんが、それについては申し訳ありません)。
(2): YAPSY プラグインは pickle 化できないため、サブプロセスに送信できません。
(3):exec()
実行のためにフリー変数を含むコードを使用しません。それが呼び出されたスコープが表示されないため、プラグイン関数のフリー変数をすべて見つける必要があります (実行時に生成されたラッパーを使用します。このような:
def no_arg_plugin_call():
plugin.method(something, from_, locals_)
と pass no_args_plugin_call.__code__
) をラップして保管しますlocals()
。また、環境全体のディープ コピーは、(1) と同じくらいコストがかかります。
PS。「フィールド」とは「属性」を意味します。なぜなら、私は (残念ながら) Java などで育ってきたからです。
PPS。YAPSY に似た (すべての機能を備え、軽量である必要がある) プラグイン システムについて聞いたことがあれば、それで十分です ;)