2009-08-11 5 views
10

私はJavaでイベントをリッスンし、Jythonで処理するフレームワークを構築しています。異なるイベントタイプが異なるスクリプトに送信されます。Javaから実行するマルチスレッドのjythonスクリプト

PythonInterpreter.exec()が呼び出されたときにjythonがスクリプトをコンパイルするのにかなり時間がかかるので、スクリプトをあらかじめコンパイルする必要があります。複数があることが起こるかもしれない - イベントは私の難問のための今すぐ

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

に来るようPyCodeコンパイルされたオブジェクトがリポジトリにプッシュして使用される

// 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"); 

:私はそれを次のようにやっています特定のタイプのイベントが同時に発生するため、複数のスクリプトインスタンスが同時に実行されます。

ほとんどすべてのスクリプトは、おそらく短命のままです - 最大100行、ループなし。番号と頻度は完全にランダム(ユーザーが生成したイベント)で、イベントの種類ごとに1秒あたり約0〜約200になります。

これを行うにはどうすればよいでしょうか?私はいくつかの可能性を見ています:トリガーイベントポイントで

  1. 使用同期 - これは、同じスクリプトの複数のインスタンスを妨げるだけでなく、イベントは、彼らが
  2. は、プールを作成する必要があります限り迅速に処理されません最大の問題はおそらくプールのサイズを最適化することでしょう。
  3. 必要に応じていつでも親からスクリプトオブジェクトを動的に複製してから、exec()が終了するとそのオブジェクトを破棄して、遅延を取り除きますコンパイルからはまだクローンメソッドに存在する

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

だから、どんな考えですか? ;)

答えて

3

PyCodeのインスタンスは不変ではありません(クラスには多くのパブリックメンバーがいます)。

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

私は次のようになります。あなたが、必要な時はいつでもあなたは、スクリプトのためPyCodeインスタンスを生成するコンストラクタを使用することができます

// 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 }); 

あなたはこのコードを使用して、再利用可能なスクリプトをプリコンパイルすることができますまずはこれが良いことではないことを認め、おそらく私のJythonの経験がないことについて話をするでしょう。ただし、毎回コンパイルするよりもはるかに高速です。このコードはJython 2.2.1で動作しますが、Jython 2.5ではコンパイルされません。

+0

ニース!最初のModule.compile(...)が呼び出される前に、PythonInterpreterのインスタンスを作成しなければならないことに注意してください。そうでない場合は、SyspathJavaLoaderからNullPointerExceptionがスローされます。loadClass() あなたは最も役に立ちました。今私がしなければならないのは、これを動的にサイズ変更可能なスクリプトのプールに統合することです。 – nEJC

+0

Jython 2.5の同等の機能はどれですか? – Laurent

+0

@Laurentは - 私はこの答え興味深い – McDowell

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 
+0

投稿が、私の知る限りではPythonInterpreterはスレッドセーフではありませんので、いや、私はそのおそらくない良いアイデアので(少なくとも私にとっては)、この地域では見ていません...しかし – nEJC

+0

はい、PythonInterpreterはスレッドセーフではありません。これが私がこのようにした理由です。 pi.eval( "action.execute")は、メソッドのインスタンスをJavaオブジェクトとしてのみ提供し、実行しません。 – Ron

関連する問題