Skip to content

bpo-30439: Add some helpful low-level functions for subinterpreters. #1802

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
8eb5adf
Add the _interpreters module to the stdlib.
ericsnowcurrently Dec 14, 2016
457567f
Add create() and destroy().
ericsnowcurrently Dec 29, 2016
e6af9f3
Finish nearly all the create/destroy tests.
ericsnowcurrently Jan 1, 2017
335967e
Add run_string().
ericsnowcurrently Dec 29, 2016
d2df973
Get tricky tests working.
ericsnowcurrently Jan 2, 2017
b70a496
Add a test for a still running interpreter when main exits.
ericsnowcurrently Jan 2, 2017
6f2d28f
Add run_string_unrestricted().
ericsnowcurrently Jan 4, 2017
80a931b
Exit out of the child process.
ericsnowcurrently Jan 4, 2017
6aa7d9c
Resolve several TODOs.
ericsnowcurrently Jan 4, 2017
083e13c
Set up the execution namespace before switching threads.
ericsnowcurrently Jan 4, 2017
ce081a7
Run in a copy of __main__.
ericsnowcurrently Jan 4, 2017
ec05cf5
Close stdin and stdout after the proc finishes.
ericsnowcurrently Jan 4, 2017
fe90466
Clean up a test.
ericsnowcurrently Jan 4, 2017
9082017
Chain exceptions during cleanup.
ericsnowcurrently Jan 4, 2017
21865d4
Finish the module docs.
ericsnowcurrently Jan 4, 2017
0342a4f
Fix docs.
ericsnowcurrently May 23, 2017
e9d9b04
Fix includes.
ericsnowcurrently Dec 5, 2017
722ae94
Add _interpreters.is_shareable().
ericsnowcurrently Nov 28, 2017
061ae13
Add _PyObject_CheckShareable().
ericsnowcurrently Dec 4, 2017
9a365ec
Add _PyCrossInterpreterData.
ericsnowcurrently Dec 4, 2017
8f299d4
Use the shared data in run() safely.
ericsnowcurrently Dec 7, 2017
92029a1
Do not use a copy of the __main__ ns.
ericsnowcurrently Dec 7, 2017
52c9c2f
Never return the execution namespace.
ericsnowcurrently Dec 8, 2017
a797883
Group sharing-related code.
ericsnowcurrently Dec 8, 2017
777838a
Fix a refcount.
ericsnowcurrently Dec 8, 2017
ab8f175
Add get_current() and enumerate().
ericsnowcurrently Dec 29, 2016
c50c51c
Add is_running().
ericsnowcurrently Dec 29, 2016
271d20d
Add get_main().
ericsnowcurrently Jan 4, 2017
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
90 changes: 90 additions & 0 deletions Doc/library/_interpreters.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
:mod:`_interpreters` --- Low-level interpreters API
===================================================

.. module:: _interpreters
:synopsis: Low-level interpreters API.

.. versionadded:: 3,7

--------------

This module provides low-level primitives for working with multiple
Python interpreters in the same runtime in the current process.

More information about (sub)interpreters is found at
:ref:`sub-interpreter-support`, including what data is shared between
interpreters and what is unique. Note particularly that interpreters
aren't inherently threaded, even though they track and manage Python
threads. To run code in an interpreter in a different OS thread, call
:func:`run_string` in a function that you run in a new Python thread.
For example::

id = _interpreters.create()
def f():
_interpreters.run_string(id, 'print("in a thread")')

t = threading.Thread(target=f)
t.start()

This module is optional. It is provided by Python implementations which
support multiple interpreters.

It defines the following functions:

.. function:: enumerate()

Return a list of the IDs of every existing interpreter.


.. function:: get_current()

Return the ID of the currently running interpreter.


.. function:: get_main()

Return the ID of the main interpreter.


.. function:: is_running(id)

Return whether or not the identified interpreter is currently
running any code.


.. function:: create()

Initialize a new Python interpreter and return its identifier. The
interpreter will be created in the current thread and will remain
idle until something is run in it.


.. function:: destroy(id)

Finalize and destroy the identified interpreter.


.. function:: run_string(id, command)

A wrapper around :c:func:`PyRun_SimpleString` which runs the provided
Python program in the main thread of the identified interpreter.
Providing an invalid or unknown ID results in a RuntimeError,
likewise if the main interpreter or any other running interpreter
is used.

Any value returned from the code is thrown away, similar to what
threads do. If the code results in an exception then that exception
is raised in the thread in which run_string() was called, similar to
how :func:`exec` works. This aligns with how interpreters are not
inherently threaded. Note that SystemExit (as raised by sys.exit())
is not treated any differently and will result in the process ending
if not caught explicitly.


.. function:: run_string_unrestricted(id, command, ns=None)

Like :c:func:`run_string` but returns the dict in which the code
was executed. It also supports providing a namespace that gets
merged into the execution namespace before execution. Note that
this allows objects to leak between interpreters, which may not
be desirable.
1 change: 1 addition & 0 deletions Doc/library/concurrency.rst
Original file line number Diff line number Diff line change
Expand Up @@ -29,3 +29,4 @@ The following are support modules for some of the above services:
_thread.rst
_dummy_thread.rst
dummy_threading.rst
_interpreters.rst
14 changes: 14 additions & 0 deletions Include/internal/pystate.h
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,20 @@ PyAPI_FUNC(_PyInitError) _PyPathConfig_Calculate(
PyAPI_FUNC(void) _PyPathConfig_Clear(_PyPathConfig *config);


/* Cross-interpreter data sharing */

struct _cid;

typedef struct _cid {
void *data;
PyObject *(*new_object)(struct _cid *);
void (*free)(void *);

PyInterpreterState *interp;
PyObject *object;
} _PyCrossInterpreterData;


/* Full Python runtime state */

typedef struct pyruntimestate {
Expand Down
Loading