Skip to content

SharedInterpreter vs SubInterpreter

Nate Jensen edited this page Dec 15, 2021 · 2 revisions

In the Jep Java API, there are two types of Python interpreters you can use. The API is intended to not be too difficult to switch between them, but depending on what you're doing in Python that may not be easy, therefore you should start your use of Jep with the hopefully correct selection.

SharedInterpreters

SharedInterpreters were introduced in Jep 3.8. A SharedInterpreter is an embedded Python interpreter that does not use the CPython sub-interpreter APIs. You can think of them as a single Python interpreter inside Jep/Java, but most things are still isolated. Specifically, each SharedInterpreter instance has its own set of globals so running Python code in one SharedInterpreter will not affect running code in another SharedInterpreter since they do not share scope. What they do share, however, is sys.modules, and therefore all imported modules. If you're used to using SubInterpreters and shared modules, you can think of SharedInterpreters as automatically sharing all modules that get imported.

You'll notice you can only use one JepConfig instance for all your SharedInterpreters, while each SubInterpreter can have its own JepConfig. That's due to SharedInterpreters essentially being the same Python interpreter, just with different globals on different threads.

SubInterpreters

SubInterpreters are the original Jep Python interpreters. If you used Jep on a release earlier than 3.8 you were using sub-interpreters. Sub-interpreters use the CPython sub-interpreter APIs to create a sub-interpreter per thread. SubInterpreters are mostly sandboxed and isolated from each other. The exception to this can be CPython extensions, such as numpy. As an example, if a CPython extension has a global static variable in its C code that does not account for sub-interpreters, then that variable exists only once in the process and across all sub-interpreters. Therefore, changing that variable will result in changing that setting across all sub-interpreters.

Sub-interpreters may run into trouble with CPython extensions. Since most CPython extensions were written without sub-interpreters in mind, they can have issues such as when they are initialized a second time (in a second sub-interpreter) or when a sub-interpreter is closed and cleans up memory. For this reason, Jep added the concept of shared modules to sub-interpreters. These are modules that you specifically designate as they should be shared across sub-interpreters.

Historically the CPython sub-interpreters APIs have been stable but not used much. There is a Python ticket to make a separate GIL per sub-interpreter. That is a significant undertaking but if it is ever completed then SubInterpreters will likely be faster than SharedInterpreters.

Which Should I Use

Use SharedInterpreters if

  • you are brand new to Jep and are not sure. It is easier to go from using SharedInterpreters to SubInterpreters than the other way around.
  • you want to use a lot of CPython extension modules

Use SubInterpreters if

  • you used Jep instances in Jep 3.x and want to retain the same behavior
  • you need your interpreters as isolated as possible
Clone this wiki locally