如何从java运行multithreadingjython脚本?
我正在构建一个Java框架,它将监听事件,然后在Jython中处理它们。 不同的事件类型将被发送到不同的脚本。
由于在调用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行,没有循环。 数字和频率是完全随机的(用户生成的事件),每个事件类型可以是每秒0到大约200。
最好的方法是什么? 我正在寻找一些可能性:
- 在触发事件点使用同步 – 这将阻止同一脚本的多个实例,但事件也不会像它们应该那样快地处理
- 通过克隆原始PyCode对象以某种方式创建一个相同类型的脚本池 – 最大的问题可能是优化池大小
- 在需要时从父进程动态克隆脚本对象,然后在exec()完成时丢弃它 – 这样从编译中删除了滞后但它仍然存在于克隆方法中
2号和3号的组合可能是最好的 – 创建动态池大小?
那么,有什么想法吗? ;)
遗憾的是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 clazz = BytecodeLoader.makeClass(name, null, buffer); final Constructor 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下编译(也不会在你的编译器下)。
PythonInterpreter很昂贵,这段代码只使用一个。
#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