-
-
Notifications
You must be signed in to change notification settings - Fork 30.5k
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
Add a Module Def Slot for Supporting Multiple Interpreters #104108
Comments
The basic idea: main...ericsnowcurrently:module-def-slot-supports-interpreters. |
related: gh-98627 |
Thanks @ericsnowcurrently. This looks great. To clarify for those who weren't present present in our discussion, all HPy modules use multi-phase init so without this there is no way for a module in HPy to specify whether it supports multiple interpreters or not. |
Sounds reasonable, but let's get the exact meaning of When a module supports multiple interpreters, it usually also supports clean tear-down, repeated initialization, and multiple module instances loaded in a single interpreter. (The module isotlation howto has more Background info.) For Will it really be “can only be loaded in one interpreter” (to check it, CPython will need something like a process-wide mapping of |
(If it turns out that each project needs slightly different semantics, they could also do the opt-out themselves -- though maybe CPython could provide better ways to do different checks.) |
Good point. I was certainly thinking of PEP 630 when talking about "supports multiple interpreters". The 0 value would match what the HPy folks are interested in. I'll make sure the docs are clear about the meaning.
I was planning to start with "can only be loaded in the main interpreter" since it's simpler. However, it should probably be "can only be loaded once in the process", since we don't know how well the module may support being loaded more than once. I suppose that "once" could technically be in any interpreter, but I don't see a big advantage to supporting that immediately. As to knowing if it was imported already, we can make use of
I'd like to keep things focused for now. We can circle back to a more detailed slot if the need arises. I have some ideas on that. |
OK, “once in the process, and only in the main interpreter” makes sense. If it's easy to implement just “once per process” I'd go with that, so we don't have another place where the concept of “main interpreter” leaks to user code. “Once per process” is safe/restrictive enough for modules that use C statics, and useful for many use cases -- especially the “MVP” (just starting out, will read up on details later) case. So adding it to C API makes sense.
I do too: I'd like to make it easy for people to do their own checking when they outgrow |
Chiming in to clarify some of the HPy specifics: tl;dr: I believe that HPy has a reasonable workaround, so the issue is not as pressing as we originally thought, but I personally think that explicit API with good docs is better than implicit assumptions inferred from (non) presence of multi-phase init.
This is indeed very HPy specific. The main motivation for requesting the flag was not The main motivation for HPy was that we'd like to have a way to say: although this extension uses multiphase init, please treat it like single phase init. Main use case for that that I see is migration of legacy extensions: the user may not be ready or willing yet to asses all the implications of what it means to support multiple interpreters, but they still want to migrate to HPy for other reasons. So for that they want to stick to the original semantics (whatever it was). Maybe one can think of similar situation on CPython? Can multi-phase init be useful on its own without subinterpreters support? There are few possible workarounds for HPy:
In HPy we still plan to have something like the flags you introduce here. In general, I think that some explicit flags that tell the interpreter what expectations the extension has is a good thing from usability and documentation point of view. Such flags may not only be related to subinterpreters, but in the future to nogil, JIT compilation, ... Maybe they should be a bitset to avoid potential explosion and allow fine grained configuration, or just multiple "flag slots" (adding few things to module spec should not really make significant memory footprint increase). |
+1 FWIW, I took a stab at something like that yesterday for this issue, but backed off when it started to get more complex than I can justify at the moment. 🙂 |
IMO, a bitset would itself be an explosion. I wouldn't want to encourage people to check for the different aspects of isolation individually. And I wouldn't want to write tests to check CPython does the right checks. I think the 3 levels, plus the ability to fail at runtime in more nuanced cases, are good. |
FYI, I've merged my PR but I'm open to further tweaks. I'll also get back to adding docs in the next few weeks. |
* main: pythongh-99113: Add PyInterpreterConfig.own_gil (pythongh-104204) pythongh-104146: Remove unused var 'parser_body_declarations' from clinic.py (python#104214) pythongh-99113: Add Py_MOD_PER_INTERPRETER_GIL_SUPPORTED (pythongh-104205) pythongh-104108: Add the Py_mod_multiple_interpreters Module Def Slot (pythongh-104148) pythongh-99113: Share the GIL via PyInterpreterState.ceval.gil (pythongh-104203) pythonGH-100479: Add `pathlib.PurePath.with_segments()` (pythonGH-103975) pythongh-69152: Add _proxy_response_headers attribute to HTTPConnection (python#26152) pythongh-103533: Use PEP 669 APIs for cprofile (pythonGH-103534) pythonGH-96803: Add three C-API functions to make _PyInterpreterFrame less opaque for users of PEP 523. (pythonGH-96849)
…pythongh-104148) I'll be adding a value to indicate support for per-interpreter GIL in pythongh-99114.
Docs was added in #107403, so It's done :) |
PEP 489 is clear that extension modules implementing multi-phase init are expected to support use in multiple interpreters. However, there are two situations where that mandate isn't sufficient:
In both cases a new module def slot (the same one, in fact) is a correct solution.
For per-interpreter GIL, PEP 684 specifies that we must add a module def slot for opting in to supporting per-interpreter GIL.
For HPy, the situation was pointed out to me by @hodgestar during a conversation at PyCon.
CC @encukou
I propose the following solution:
Py_mod_multiple_interpreters
module def slot_PyImport_CheckSubinterpIncompatibleExtensionAllowed()
when appropriate inPyModule_FromDefAndSpec2()
The slot value may be one of the following:
0
- does not support multiple interpreters (for HPy)1
- supports multiple interpreters (the default)2
- supports per-interpreter GILIt would probably make sense to define a constant (macro) for each of those.
Linked PRs
The text was updated successfully, but these errors were encountered: