-
Notifications
You must be signed in to change notification settings - Fork 150
Performance Considerations
Jep is used on production systems that run significant amounts of Python in mission critical servers. In these situations there are some recommended best practices.
You can leak Python objects (or Java objects in Python!) if you continually create new variables in an interpreter's global scope. There's a few different techniques you can use to ensure this doesn't happen. In no particular order:
- Execute most of your Python code in functions, so any variables created exist only temporarily in local scope. The Python garbage collector will take care of variables after they go out of scope. For example:
def foo():
args = get_args()
values = pre_process(args)
doMath(values)
interp.exec("foo()");
where foo() does all the work. args and values will go out of scope and be automatically cleaned up.
- Delete any variables created by
jep.setValue(String name, Object var);
once you are done with them. For example:
interp.set("x", javaObj);
interp.exec("result = foo(x)");
Object result = interp.getValue("result");
interp.exec("del x");
interp.exec("del result");
You can also shortcut this with Python code like:
for g in globals():
if some_condition(g):
del g
- Close the Jep interpreters when you are done with them. This is easiest using Java try-with-resource, for example:
try(Jep interp = new SharedInterpreter()) {
// runScript, invoke, exec, and other fun things
}
Starting and stopping Python interpreters, while fast, is relatively slow in comparison to using an already initialized interpreter. This becomes even more noticeable as the number of modules that get imported into the interpreter grows. In these cases you should strongly consider retaining your Interpreter instances and reusing them.
See also Jep and the GIL.
Jep requires that the thread that initializes the interpreter is the same thread for any operations on the interpreter. If you want to reuse Interpreters for speed or stateful reasons, and you also want to multithread your calls to Python, a useful technique is to pool Interpreters. An accompanying factory class can create and initialize your Interpreters on demand for the pool, and you can limit the number of threads in the pool to ensure that the Python components do not overwhelm the rest of the system.