10

イベントをリッスンしてからJythonで処理するフレームワークをJavaで構築しています。さまざまなイベント タイプがさまざまなスクリプトに送信されます。

PythonInterpreter.exec() が呼び出されると、jython はスクリプトをコンパイルするのにかなりの時間がかかるため、スクリプトをプリコンパイルする必要があります。私は次の方法でそれをやっています:

// initialize the script as string (would load it from file in final version)
String script = "print 'foo'";
// get the compiled code object
PyCode compiled = org.python.core.__builtin__.compile( script, "<>", "exec" );

PyCode でコンパイルされたオブジェクトはリポジトリにプッシュされ、イベントが受信されると使用されます。

PythonInterpreter pi = new PythonInterpreter();
pi.set( "variable_1", "value_1");
pi.set( "variable_x", "value_x");
pi.exec( compiled );

ここで、私の難問について説明します。特定のタイプの複数のイベントが同時に発生する可能性があります。したがって、スクリプトの複数のインスタンスが同時に実行されます。

ほとんどすべてのスクリプトはおそらく短命のままで、最大 100 行、ループはありません。数と頻度は完全にランダム (ユーザー生成イベント) で、イベント タイプごとに 1 秒あたり 0 から約 200 になる可能性があります。

それを行う最善の方法は何ですか?私はいくつかの可能性を見ています:

  1. トリガーイベントポイントで同期を使用します-これにより、同じスクリプトの複数のインスタンスが防止されますが、イベントは本来の速度で処理されません
  2. 元の PyCode オブジェクトのクローンを作成することによって何らかの方法で入力された同じタイプのスクリプトのプールを作成します。おそらく最大の問題は、プール サイズの最適化です。
  3. 必要に応じて親からスクリプト オブジェクトを動的に複製し、exec() が終了したら破棄します。このようにして、コンパイルからラグが取り除かれますが、クローン メソッドにはまだ存在します。

おそらく 2 番と 3 番の組み合わせが最適でしょう - 動的プール サイズを作成しますか?

それで、何か考えはありますか?;)

4

2 に答える 2

3

インスタンスが不変ではないのは残念ですPyCode(クラスには多くの public メンバーがあります)。

次のコードを使用して、再利用可能なスクリプトをプリコンパイルできます。

// TODO: generate this name
final String name = "X";
byte[] scriptBytes = PyString.to_bytes(script);
CompilerFlags flags = Py.getCompilerFlags();
ByteArrayOutputStream ostream = new ByteArrayOutputStream();
Module.compile(parser.parse(new ByteArrayInputStream(scriptBytes), "exec",
    "<>", flags), ostream, name, "<>", false, false, false, flags);
byte[] buffer = ostream.toByteArray();
Class<PyRunnable> clazz = BytecodeLoader.makeClass(name, null, buffer);
final Constructor<PyRunnable> constructor = clazz
    .getConstructor(new Class[] { String.class });

その後、コンストラクターを使用して、必要なときにいつでもスクリプトの PyCode インスタンスを生成できます。

 PyRunnable r = constructor.newInstance(name);
 PyCode pc = r.getMain();

これは良い方法ではなく、おそらく Jython の経験不足について多くを語っていることを認めるのは私が最初です。ただし、毎回コンパイルするよりもはるかに高速です。このコードは Jython 2.2.1 で動作しますが、Jython 2.5 ではコンパイルできません (あなたのものも同様です)。

于 2009-08-13T17:43:27.653 に答える
1

PythonInterpreter は高価です。このコードでは 1 つしか使用しません。

#action.py
def execute(filename, action_locals):
    #add caching of compiled scripts here
    exec(compile(open(filename).read(), filename, 'exec'), action_locals)

//class variable, only one interpreter
PythonInterpreter pi;

//run once in init() or constructor
pi = new PythonInterpreter();//could do more initialization here
pi.exec("import action");

//every script execution
PyObject pyActionRunner = pi.eval("action.execute");
PyString pyActionName = new PyString(script_path);
PyDictionary pyActionLocals = new PyDictionary();
pyActionLocals.put("variable_1", "value_1");
pyActionLocals.put("variable_x", "value_x")
pyActionRunner.__call__(pyActionName, pyActionLocals);

#example_script.py
print variable_1, variable_x
于 2009-11-26T23:07:10.573 に答える