On 17Mar2020 1447, Mark Shannon wrote:
On 16/03/2020 3:04 pm, Victor Stinner wrote:
In short, the answer is yes.
I said "no" then and gave reasons. AFAICT no one has faulted my reasoning.
I said "yes" then and was also not faulted.
Let me reiterate why using a thread-local variable is better than
passing the thread state down the C stack.
1. Using a thread-local variable for the thread state requires much
smaller changes to the code base.
Using thread-local variables enforces a threading model on the host
application, rather than working with the existing threading model. So
anyone embedding is forced into *significantly* more code as a result.
We can (and should) maintain a public-facing API that uses TLS to pass
the current thread state around - we have compatibility constraints. But
we can also add private versions that take the thread state (once you've
started trying/struggling to really embed CPython, you'll happily take a
dependency on "private" APIs).
If the only available API requires TLS, then you're likely to see the
caller wrap it all up in a function that updates TLS before calling. Or
alternatively, introduce dedicated threads for running Python snippets
on, and all the (dead)locking that results (yes, I've done both).
Our goal as core CPython developers should be to sacrifice our own
effort to reduce the effort needed by our users, not to do things that
make our own lives easier but harm them.
2. Using a thread-local variable is less error prone. When passing
tstate as a parameter, what happens if the tstate argument is from a
different thread or is NULL? Are you adding checks for those cases?
What are the performance implications of adding those checks?
Undefined behaviour is totally acceptable here. We can assert in debug
builds - developers who make use of this can test with debug builds.
3. Using a thread-local variable is likely to be a little bit faster.
Passing an argument down the stack increases register pressure and spills.
Accessing a thread-local is slower at the point of access, but the cost
is incurred only when it is needed, so is cheaper overall.
Compilers can optimise parameters/locals in ways that are far more
efficient than they can do for anything stored outside the call stack.
Especially for internal calls. Going through public/exported functions
is a little more restricted in terms of optimisations, but if we
identify an issue here then we can work on that then.
[OTHER POST]
Just to be clear, this is what I mean by a thread local variable:
https://godbolt.org/z/dpSo-Q
Showing what one particular compiler generates for one particular
situation is terrible information (I won't bother calling it "evidence").
One motivation is to ease the implementation of subinterpreters (PEP
554). But PEP 554 describes more than public API than the
implementation.
I don't see how this eases the implementation of subinterpreters.
Surely it makes it harder by causing merge conflicts.
That's a very selfish point-of-view :)
It eases it because many more operations need to know the current Python
"thread" in order to access things that used to be globals, such as
PyTypeObject instances. Having the thread state easily and efficiently
accessible does make a difference here.
The long-term goal is to be able to run multiple isolated interpreters
in parallel.
An admirable goal, IMO.
But how is it to be done? That is the question.
By isolating thread states properly from global state.
Sorry about that :-/ A lot of Python internals should be modified to
implement subinterpreters.
I don't think they *should*. When they *must*, then do that.
Changes should only be made if necessary for correctness or for a
significant improvement of performance.
They must - I think Victor just chose the wrong English word there.
Correctness is the first thing to fall when you access globals in
multithreaded code, and the CPython code base accesses a lot of globals.
Cheers,
Steve
_______________________________________________
Python-Dev mailing list -- python-dev@python.org
To unsubscribe send an email to python-dev-le...@python.org
https://mail.python.org/mailman3/lists/python-dev.python.org/
Message archived at
https://mail.python.org/archives/list/python-dev@python.org/message/5FB5PNH2H72ZAAN7TEDR3NS45H34ELEY/
Code of Conduct: http://python.org/psf/codeofconduct/