Repository navigation
Improve concurrent.interpreters documentation #142041
Copy link
Copy link
Open
Labels
Description
Documentation
We need a better documentation for https://docs.python.org/3/library/concurrent.interpreters.html
I tried this, but I don't understand
- how to use queue
- prepare_main purpose
- exec parameters like dedent
- I got funny crashes
####################################################################################################
from concurrent import interpreters as CI
from pprint import pprint
from textwrap import dedent
import queue
####################################################################################################
main_interpreter = CI.get_main()
print(f"Main is {main_interpreter}")
current_interpreter = CI.get_current()
print(f"Current is {current_interpreter}")
queue = CI.create_queue()
def task_runner(index):
print("Task runner", index)
print(f" Current is {current_interpreter}")
globals_ = globals()
# pprint(globals_)
print(" Globals:")
for key, value in globals().items():
if key == '__builtins__':
print(f" __builtins__: ...")
else:
print(f" {key}: {value}")
# Crash
# Main is Interpreter(0)
# Current is Interpreter(1)
# concurrent.interpreters.ExecutionFailed: NameError: name 'foo' is not defined
#! print(foo)
# Block
#! print(f" #{index} from queue {queue.get()}")
return 'ok'
# if True:
if current_interpreter is main_interpreter:
# queue = CI.create_queue()
interpreters = []
NUMBER_OF_INTERPRETERS = 4
for i in range(NUMBER_OF_INTERPRETERS):
_ = CI.create()
# Bind objects in the interpreter’s __main__ module
_.prepare_main(ns=None, foo=123)
interpreters.append(_)
for _ in CI.list_all():
print(f"Interpreter id {_.id} running {_.is_running()} whence '{_.whence}'")
print("Call...")
print()
# exec(code, /, dedent=True)
interpreters[0].exec(dedent('''
print(f"Exec hello {foo}")
'''))
print()
rc = interpreters[0].call(task_runner, 0)
print(rc)
print()
threads = []
for i in range(NUMBER_OF_INTERPRETERS):
thread = interpreters[i].call_in_thread(task_runner, i)
print(f"Thread #{i} {thread}")
threads.append(thread)
NUMBER_OF_TASKS = 10
for i in range(NUMBER_OF_TASKS):
queue.put(i)
for thread in threads:
thread.join()
# print()
# print(queue)
# Block main
#! print(queue.get())
# try:
# except queue.ShutDown:
# pass
else:
passLinked PRs
Metadata
Metadata
Assignees
Labels
Projects
- StatusShow more project fieldsTodo
- StatusShow more project fieldsTodo
Activity
picnixz commentedon Nov 28, 2025
I think
dedentis actually self-explanatory, that is, it should dedent the code you give so that you don't need to worry about indented script. The following would raise SyntaxError or something like that:The API for queues is documented in
queue.Queue(that's what the docs say). I don't think we should explain more. What matters is that, for subinterpreters, you cannot just usequeue.Queue()to share your data. You need this special queue. Which objects could be shared is explained in https://docs.python.org/3/library/concurrent.interpreters.html#sharing-objects.prepare_mainmay indeed have a bit more explanations, like a "roughly equivalent to" example. I cannot say I know its purpose but AFAICT, it's essentially a way to populate the__main__namespace with some objects (it's as if you were writing__main__.update(ns)for the__main__module of the subinterpreter being considered)."funny crashes" isn't enough to understand your issues; please be more precise. We could have a FAQ for such issues though.
cc @ZeroIntensity @ericsnowcurrently
FabriceSalvaire commentedon Nov 28, 2025
I guessed what is dedent, but I probably had an issue with my experimental code...
Funny crashes: For example,
#! print(foo). It looks like the executed code is different due to this line.Indeed, I managed to populate the globals, but it looks like it depends on my code. So I am confused...
But queue doesn't work on my code, so I missed something...
However, I converted this example in the doc and it runs 100% on all the cpu cores:
See code in
/usr/lib64/python3.14/concurrent/future/interpreter.pyFabriceSalvaire commentedon Nov 28, 2025
I annotated the code of
concurrent/future/interpreter.pyoutput
FabriceSalvaire commentedon Nov 28, 2025
I think we need a tutorial.
Things are always obvious to core dev.
Also, a graphic could help to quickly understand how it works (interpreters, threads).
FabriceSalvaire commentedon Nov 28, 2025
So multicore is due to
Main C Python interpreter / thread - do a function call to another ->* C Python interpreter running in another thread
The code path is independent and can be scheduled in parallel to a CPU core.
It returns a value to the main interpreter.
Task scheduling is done by main interpreter.
This is more simple than a multi-processes spawning and communication.
picnixz commentedon Nov 28, 2025
Not really. I can mostly guess what
prepare_maindoes because of how it's being phrased.This may be a legitimate bug. Do you have a self-contained example? please show us the traceback as well.
To be clear, I am not against improving the docs, but I would rather see a separate guide for subinterpreters rather than changing the current page (like we did for
asyncio). We only have two core devs that are working actively on subinterpreters (those that I tagged) and we simply don't have enough people that can write this kind of guide so I guess this issue will likely stay open for some time. I will leave what to write and where to write to Eric.ZeroIntensity commentedon Nov 28, 2025
prepare_mainjust lets you inject variables into a subinterpreter's namespace. Feel free to send a PR clarifying things and tag me for a review. For a general subinterpreter tutorial, I think Eric is working on a concurrency HOWTO that deals with that.pythongh-142041: Improve concurrent.interpreters documentation
mvanhorn commentedon Mar 9, 2026
I've submitted a PR to improve the documentation: #145657
It addresses the specific pain points mentioned in this issue:
prepare_mainhas a clear explanation and usage examplededentparameter onexechas been removed (it doesn't exist in the implementation)