But that is not what threading means. If you want "completely independent interpreters" just fork. Threading means you share everything.
> Then the GIL can be discarded altogether
And then you start sharing variables between interpreters, and you gets lots of little baby GILs to contend with! How fun will that be? Not very.
I think the only way to do that would be to have a reentrant lock for each object individually. Isn't that potentially a big performance issue?
I think that is the main reason behind this quote from the article:
> Several attempts have been made over the years and failed to do it without sacrificing single-threaded performance.
However, built on top of CPython's C API are a huge pile of libraries that assume they can manipulate global or per-data-structure state without locking.
Also how is this different then problems faced when using multiprocessing style parallelism with the same library?
The readline module uses libreadline, which maintains internal global state on the C side.
The standard library has lists and dictionaries, which are not thread-safe to access from two threads simultaneously, and are not in any way locked.
Locking lists and dicts, etc would not be a reasonable thing to do. There must be some granularity in synchronization, it's clearly not a good idea to attempt to allow mutating any object from multiple threads without explicit locking.
Things like readline are issues that programmers have to deal with when writing multi threaded code in any language. There are libs which are not thread safe or which have global state or need special handling with threads (e.g. OpenGL). That's no reason to disallow threading completely.
However, this might be a big culture shock issue if Python were to suddenly start supporting proper concurrency without GIL. None of the libraries document whether they are thread safe or not, so there would be surprises ahead.
Although PHP7 does have some workarounds to improve the performance of this mode, involving implementing thread-local storage on certain operating systems..
E.g. https://bitbucket.org/tpn/pyparallel/src/3be2954508f9938b85a...
It's slower than accessing a struct, sure:
5982: if (ctx) {
000000001E1A808B 8B 0D FF 7C 28 00 mov ecx,dword ptr [_tls_index (1E42FD90h)]
000000001E1A8091 BA 80 29 00 00 mov edx,2980h
000000001E1A8096 48 89 83 90 02 00 00 mov qword ptr [rbx+290h],rax
000000001E1A809D 65 48 8B 04 25 58 00 00 00 mov rax,qword ptr gs:[58h]
000000001E1A80A6 48 8B 04 C8 mov rax,qword ptr [rax+rcx*8]
000000001E1A80AA 48 8B 0C 02 mov rcx,qword ptr [rdx+rax]
000000001E1A80AE 48 85 C9 test rcx,rcx
000000001E1A80B1 74 70 je new_context+253h (1E1A8123h)
But think of the big picture: I use TLS everywhere for PyParallel, and PyParallel has awesome performance, so eh, net win.> One should be able to support many low-overhead independent interpreter instances on a single thread
Why? What problem does that solve?
The use of the globals in the CPython interpreter are a fairly large design mistake that has prevented Python from having as much reach as other systems. The whole embedding vs extending debate is because of those globals and that CPython has been historically difficult to embed properly. Lua on the other hand, is easy to both embed and extend.
I'd love to use `cffi` to embed Python within itself, I cannot do that.
As to supporting multiple truly independent Python interpreters in the same process, I'm not clear on what the buys you over subinterpreters. In fact, with subinterpreters you get the benefit of the main interpreter handling the C runtime global state (env vars, command line args, the standard streams, etc.). With truly independent interpreters that's more complicated.
While it's not quite what you described, if you were to suggest that subinterpreters be made even more isolated from one another than they already are then I'd agree. :) It sounds like that's really what you're after: better isolation between interpreters in a single process.