Subj is off topic for the ticket, so I guess this discussion is better continued here.

On 15.05.2018 18:20, Mark Roseman wrote:
Mark Roseman <m...@markroseman.com> added the comment:

Hi Ivan, thanks for your detailed response. The approach you're suggesting ("Since 
the sole offender is their threading model, the way is to show them how it's defective 
and work towards improving it.") is in the end not something I think is workable.

Some historical context. Ousterhout had some specific ideas about how Tcl/Tk should be used, and that was 
well-reflected in his early control of the code base. He was certainly outspoken against threads. The main 
argument is that they're complicated if you don't know what you're doing, which included the 
"non-professional programmers" he considered the core audience. Enumerating how threads were used 
at the time, most of the uses could be handled (more simply) in other ways, such as event-driven and 
non-blocking timers and I/O (so what people today would refer to as the "node.js event model"). 
Threads (or separate communicating processes) were for long-running computations, things he always envisioned 
happening in C code (written by more "professional programmers"), not Tcl. His idea of how Tcl and 
C development would be split didn't match reality given faster machines, more memory, etc.

Very enlightening. Many thanks.

The second thing is that Tcl had multiple interpreters baked in pretty much 
from the beginning at the C level and exposed fairly early on (1996?) at the 
Tcl level, akin to PEP 554. Code isolation and resource management were the key 
motivators, but of course others followed. Creating and using Tcl interpreters 
was quick, lightweight (fast startup, low memory overhead, etc.) and easy. So 
in other words, the notion of multiple interpreters in Tcl vs. Python is 
completely different. I had one large application I built around that time that 
often ended up with hundreds of interpreters running.

Not familiar with the concept so can't say atm if tkinter can make any use of this. All tkinter-using code I've seen so far only ever uses a single tkinter.Tk() -- thus a single interpreter.

Which brings me to threads and how they were added to the language. Your guess ("My guess for 
the decision is it was the easiest way to migrate the code base") is incorrect. The idea of 
"one thread/one interpreter" was just not seen as a restriction, and was a very natural 
extension of what had come before. It fit the use cases well (AOLserver was another good example) 
and was still very understandable from the user level. Contrast with Python's GIL, etc.

I'm not actually suggesting any changes to Tcl as a language, only to its C interface (details follow). AFAIK Tcl also advertises itself as an embeddable language as its main selling point, having been developed primarity as an interface to Tk rather than a self-sufficient language (or, equivalently, this being its primary use case now). Having to do an elaborate setup with lots of custom logic to be able to embed it is a major roadblock. This can be the leverage.

From C interface's standpoint, an interpreter is effectively a bunch of data that can be passed to APIs. Currently, all Tcl_* calls with a specific interpreter instance must be made from the same thread, and this fact enforces sequential access. I'm suggesting to wrap all these public APIs with an interpreter-specific lock -- so calls can be made from any OS thread and the lock enforces sequential access. For Tcl's execution model and existing code, nothing will change. The downside (that will definitely be brought up) is the overhead, of course. The question is thus whether the above-mentioned benefit outweighs it.

With that all said, there would be very little motivation to change the Tcl/Tk side to allow multiple threads 
to access one interpreter, because in terms of the API and programming model that Tcl/Tk advertises, it's 
simply not a problem. Keep in mind, the people working on the Tcl/Tk core are very smart programmers, know 
threads very well, etc., so it's not an issue of "they should know better" or "it's old." 
In other words, "show them how it's defective" is a non-starter.

The other, more practical matter in pushing for changes in the Tcl/Tk core, is 
that there are a fairly small number of people working on it, very part-time. 
Almost all of them are most interested in the Tcl side, not Tk. Changes made in 
Tk most often amount to bug fixes because someone's running into something in 
their own work. Expecting large-scale changes to happen to Tk without some way 
to get dedicated new resources put into it is not realistic.

A final matter on the practical side. As you've carefully noted, certain Tcl/Tk calls now 
happen to work when called from different threads. Consider those a side-effect of 
present implementation, not a guarantee. Future core changes could change what can be 
called from different threads, making the situation better or worse. From the Tcl/Tk 
perspective, this is not a problem, and would not be caught by any testing, etc. Even if 
it were, it likely wouldn't be fixed. It would be considered an "abuse" of 
their API (I think correctly).
My suggestion, given the philosophical and practical mismatch, is that Tkinter 
move towards operating as if the API Tk provides is inviolate. In other words, 
all calls into a Tcl interpreter happen from the same thread that created the 
Tcl interpreter. Tkinter acts as a bridge between Python and Tcl/Tk. It should 
present an API to Python programs compatible with the Python threading model. 
It's Tkinter's responsibility to map that onto Tcl/Tk's single threaded API 
through whatever internal mechanism is necessary (i.e. pass everything to main 
thread, block caller thread until get response, etc.)

That's exactly what Tkinter currently does, see the letter attached to the ticket. Writing clean and correct code is Python's principal standpoint, it doesn't use unsupported functions.

I'd go so far as to suggest that all the Tkapp 'call' code (i.e. every place that Tkinter 
calls Tcl_Eval) check what thread it's in, and issue a warning or error (at least for 
testing purposes) if it's being called from the "wrong" thread. Having this 
available in the near future would help people who are debugging what are fairly 
inexplicable problems now.

The approach of making Tkinter responsible also has the advantage of dealing 
with far more Tcl/Tk versions and builds.

Given in practice that few people are really running into things, and that if they are, they know 
enough to be able to follow the instruction "all Tkinter calls from the same thread" for 
now, add the warnings/errors in via whatever "turn on debugging" mechanism makes sense. A 
future version of Python would include a fully thread-safe Tkinter that internally makes all Tcl/Tk 
calls from a single thread, as per above.

Sorry this is so incredibly long-winded. I hope the context at least is useful 
information.

----------

_______________________________________
Python tracker <rep...@bugs.python.org>
<https://bugs.python.org/issue33479>
_______________________________________

--
--
Regards,
Ivan

_______________________________________________
Python-Dev mailing list
Python-Dev@python.org
https://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: 
https://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com

Reply via email to