Skip to content

Commit 68543fa

Browse files
b-passhenryiii
authored andcommitted
Add documentation for embeded sub-interpreters
1 parent 51764f0 commit 68543fa

2 files changed

Lines changed: 164 additions & 21 deletions

File tree

docs/advanced/embedding.rst

Lines changed: 157 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -237,31 +237,172 @@ global data. All the details can be found in the CPython documentation.
237237

238238
Creating two concurrent ``scoped_interpreter`` guards is a fatal error. So is
239239
calling ``initialize_interpreter`` for a second time after the interpreter
240-
has already been initialized.
240+
has already been initialized. Use :class:`scoped_subinterpreter` to create
241+
a sub-interpreter. See :ref:`subinterp` for important details on sub-interpreters.
241242

242243
Do not use the raw CPython API functions ``Py_Initialize`` and
243244
``Py_Finalize`` as these do not properly handle the lifetime of
244245
pybind11's internal data.
245246

246247

248+
.. _subinterp:
249+
247250
Sub-interpreter support
248251
=======================
249252

250-
Creating multiple copies of ``scoped_interpreter`` is not possible because it
251-
represents the main Python interpreter. Sub-interpreters are something different
252-
and they do permit the existence of multiple interpreters. This is an advanced
253-
feature of the CPython API and should be handled with care. pybind11 does not
254-
currently offer a C++ interface for sub-interpreters, so refer to the CPython
255-
documentation for all the details regarding this feature.
253+
A sub-interpreter is a separate interpreter instance which provides a
254+
separate, isolated interpreter environment within the same process as the main
255+
interpreter. Sub-interpreters are created and managed with a separate API from
256+
the main interpreter. Beginning in Python 3.12, sub-interpreters each have
257+
their own Global Interpreter Lock (GIL), which means that running a
258+
sub-interpreter in a separate thread from the main interpreter can achieve true
259+
concurrency.
260+
261+
Managing multiple threads and the lifetimes of multiple interpreters and their
262+
GILs can be challenging. Proceed with caution (and lots of testing)!
263+
264+
The main interpreter must be initialized before creating a sub-interpreter, and
265+
the main interpreter must outlive all sub-interpreters. Sub-interpreters are
266+
managed through a different API than the main interpreter.
267+
268+
The sub-interpreter API can be found in ``pybind11/subinterpreter.h``.
269+
270+
The :class:`subinterpreter` class manages the lifetime of sub-interpreters.
271+
Instances are movable, but not copyable. Default constructing this class does
272+
*not* create a sub-interpreter (it creates an empty holder). To create a
273+
sub-interpreter, call :func:`subinterpreter::create()`.
274+
275+
.. warning::
276+
277+
Sub-interpreter creation acquires (and subsequently releases) the main
278+
interpreter GIL. If another thread holds the main GIL, the function will
279+
block until the main GIL can be acquired.
280+
281+
Sub-interpreter destruction temporarily activates the sub-interpreter. The
282+
sub-interpreter must not be active (on any threads) at the time the
283+
:class:`subinterpreter` destructor is called.
284+
285+
Both actions will re-acquire any interpreter's GIL that was held prior to
286+
the call before returning (or return to no active interpreter if none was
287+
active at the time of the call).
288+
289+
Once a sub-interpreter is created, you can "activate" it on a thread (and
290+
acquire it's GIL) by creating a :class:`subinterpreter_scoped_activate`
291+
instance and passing it the sub-intepreter to be activated. The function
292+
will acquire the sub-interpreter's GIL and make the sub-interpreter the
293+
current active interpreter on the current thread for the lifetime of the
294+
instance. When the :class:`subinterpreter_scoped_activate` instance goes out
295+
of scope, the sub-interpreter GIL is released and the prior interpreter that
296+
was active on the thread (if any) is reactivated and it's GIL is re-acquired.
297+
298+
The :func:`subinterpreter::activate_main()` function activates the main
299+
interpreter, acquiring it's GIL, and returns a
300+
:class:`subinterpreter_scoped_activate` instance which will automatically
301+
deactivate the main interpreter and release it's GIL when it goes out of
302+
scope, just as :class:`subinterpreter_scoped_activate` also does for
303+
sub-interpreters.
304+
305+
:class:`gil_scoped_release` and :class:`gil_scoped_acquire` can be used to
306+
manage the GIL of a sub-interpreter just as they do for the main interpreter.
307+
They both manage the GIL of the currently active interpreter, without the
308+
programmer having to do anything special or different. There is one important
309+
caveat:
310+
311+
.. note::
312+
313+
When no interpreter is active through a
314+
:class:`subinterpreter_scoped_activate` instance (such as on a new thread),
315+
:class:`gil_scoped_acquire` will acquire the **main** GIL and
316+
activate the **main** interpreter.
317+
318+
Each sub-interpreter will import a separate copy of each ``PYBIND11_EMBEDDED_MODULE``
319+
when those modules specify a ``multiple_interpreters`` tag. If a module does not
320+
specify a ``multiple_interpreters`` tag, then Python will report an ``ImportError``
321+
if it is imported in a sub-interpreter.
322+
323+
Here is an example showing how to create and activate sub-interpreters:
324+
325+
.. code-block:: cpp
326+
327+
#include <iostream>
328+
#include <pybind11/embed.h>
329+
#include <pybind11/subinterpreter.h>
330+
331+
namespace py = pybind11;
332+
333+
PYBIND11_EMBEDDED_MODULE(printer, m, py::multiple_interpreters::per_interpreter_gil()) {
334+
m.def("which", [](const std::string& when) {
335+
std::cout << when << "; Current Interpreter is "
336+
<< PyInterpreterState_GetID(PyInterpreterState_Get())
337+
<< std::endl;
338+
});
339+
}
340+
341+
int main() {
342+
py::scoped_interpreter main_int{};
343+
344+
py::module_::import("printer").attr("which")("First init");
345+
346+
{
347+
py::subinterpreter sub = py::subinterpreter::create();
348+
349+
py::module_::import("printer").attr("which")("Created sub");
350+
351+
{
352+
py::subinterpreter_scoped_activate ssa(sub);
353+
py::module_::import("printer").attr("which")("Activated sub");
354+
}
355+
356+
py::module_::import("printer").attr("which")("Deactivated sub");
357+
358+
{
359+
py::gil_scoped_release nogil;
360+
{
361+
py::subinterpreter_scoped_activate ssa(sub);
362+
{
363+
auto main_sa = py::subinterpreter::main_scoped_activate();
364+
py::module_::import("printer").attr("which")("Main within sub");
365+
}
366+
py::module_::import("printer").attr("which")("After Main, still within sub");
367+
}
368+
}
369+
}
370+
371+
py::module_::import("printer").attr("which")("At end");
372+
373+
return 0;
374+
}
375+
376+
Expected output:
377+
378+
.. code-block:: text
379+
380+
First init; Current Interpreter is 0
381+
Created sub; Current Interpreter is 0
382+
Activated sub; Current Interpreter is 1
383+
Deactivated sub; Current Interpreter is 0
384+
Main within sub; Current Interpreter is 0
385+
After Main, still within sub; Current Interpreter is 1
386+
At end; Current Interpreter is 0
387+
388+
pybind11 also has a :class:`scoped_subinterpreter` class, which creates and
389+
activates a sub-interpreter when it is constructed, and deactivates and deletes
390+
it when it goes out of scope.
391+
392+
Best Practices for sub-interpreter safety:
393+
394+
- Never share Python objects across different interpreters.
256395

257-
We'll just mention a couple of caveats the sub-interpreters support in pybind11:
396+
- Avoid global/static state whenever possible. Instead, keep state within each interpreter,
397+
such as within the interpreter state dict, which can be accessed via
398+
``subinterpreter::current().state_dict()``, or within instance members and tied to
399+
Python objects.
258400

259-
1. Sub-interpreters will not receive independent copies of embedded modules.
260-
Instead, these are shared and modifications in one interpreter may be
261-
reflected in another.
401+
- Avoid trying to "cache" Python objects in C++ variables across function calls (this is an easy
402+
way to accidentally introduce sub-interpreter bugs). In the code example above, note that we
403+
did not save the result of :func:`module_::import`, in order to avoid accidentally using the
404+
resulting Python object when the wrong interpreter was active.
262405

263-
2. Managing multiple threads, multiple interpreters and the GIL can be
264-
challenging and there are several caveats here, even within the pure
265-
CPython API (please refer to the Python docs for details). As for
266-
pybind11, keep in mind that ``gil_scoped_release`` and ``gil_scoped_acquire``
267-
do not take sub-interpreters into account.
406+
- While sub-interpreters each have their own GIL, there can now be multiple independent GILs in one
407+
program, so your code needs to consider thread safety of within the C++ code, and the possibility
408+
of deadlocks caused by multiple GILs and/or the interactions of the GIL(s) and C++'s own locking.

include/pybind11/subinterpreter.h

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -46,8 +46,9 @@ class subinterpreter_scoped_activate {
4646
/// Holds a Python subinterpreter instance
4747
class subinterpreter {
4848
public:
49-
subinterpreter() = default; /// empty/unusable, but move-assignable. use create() to create a subinterpreter.
50-
49+
/// empty/unusable, but move-assignable. use create() to create a subinterpreter.
50+
subinterpreter() = default;
51+
5152
subinterpreter(subinterpreter const &copy) = delete;
5253
subinterpreter &operator=(subinterpreter const &copy) = delete;
5354

@@ -56,14 +57,15 @@ class subinterpreter {
5657
old.istate_ = nullptr;
5758
}
5859

59-
subinterpreter &operator = (subinterpreter &&old) {
60+
subinterpreter &operator=(subinterpreter &&old) {
6061
std::swap(old.tstate_, tstate_);
6162
std::swap(old.istate_, istate_);
6263
return *this;
6364
}
6465

6566
/// Create a new subinterpreter with the specified configuration
66-
/// Note Well:
67+
/// @note This function acquires (and then releases) the main interpreter GIL, but the main
68+
/// interpreter and its GIL are not required to be held prior to calling this function.
6769
static inline subinterpreter create(PyInterpreterConfig const &cfg) {
6870
error_scope err_scope;
6971
auto main_guard = main_scoped_activate();
@@ -92,7 +94,7 @@ class subinterpreter {
9294
return result;
9395
}
9496

95-
/// Call create() with a default configuration of an isolated interpreter that disallows fork,
97+
/// Calls create() with a default configuration of an isolated interpreter that disallows fork,
9698
/// exec, and Python threads.
9799
static inline subinterpreter create() {
98100
// same as the default config in the python docs

0 commit comments

Comments
 (0)