Avoid polling in favour of Events - #7
Conversation
run_in_thread() and run_in_executor() start their job and then go into a polling mode where they check the "done" flag in a regular fashion. This is not very elegant, considering the fact that we have beautiful event classes at hand. So use them for waiting.
Instead of handling result and exceptoin on our own, make use of the fact that an executor passes the result or exception of the called function into the future. This way, we only need to have the future call event.fire() over thread boundaries (using after(0, ...)) and then can use the future to get retuen value or exception as it is available.
|
This one I leave in draft mode as I didn't test it very well until now. |
|
With this change, Perhaps this could be made safe using Thank you for your contribution. |
In https://docs.python.org/3/library/tkinter.html#threading-model, it says
I would not dare to test this on every method possible, but especially for |
|
I didn't realize it was officially documented as thread-safe. That's news to me. I once tried combining Tkinter with Trio using Trio's Guest Mode, which requires a thread-safe way to schedule a function from a worker thread to be executed on the main thread. I first tried the I just tried it again, and this time it worked without relying on There are a couple of things I'd like to ask:
|
Sorry, I may be wrong. As long as you rely on |
Yes, Future handles that automatically in this case. Serialization and deserialization would be needed if I wanted the Tk library to pass around things, as it is obviously addressed via text commands. But in this case, the Tk library only passes around the IDs of the callables (as far as I can tell), and the objects remain in the Python domain. BTW, in another documentation (https://tkdocs.com/tutorial/eventloop.html#threads), they seem to support your original standpoint, that for triggering stuff from other threads, the better way would be to use Resorting to polling still gives me a feeling of imperfection, somehow. I am still going to play around with these things and will come back in a few days after I'll have hopefully found some answers to your questions and to my own ones. Edit: It seems to me that I hope I dont talk too much uncoordinated things and it makes a little bit sense. |
|
Oh, and about your questions:
I'll try to find out whether this is actually necessary, and if so, if it is necessary for both variants. Edit: According to this line , Tcl 9.0 and newer are always threaded, older versions are under certain conditions - they seem to make the same test as you suggest. I found out that this test isn't foolproof, however - it is possible to manipulate the value in this array: both work and seem to alter the content of this array. (But who does this, deserves the consequences.)
I will do so in the next version of the PR.
Although we (seem to) have consensus that it will work anyway, I think we should treat the futures object separately. That has the very big advantage that it is possible to get the futures from wherever we want - be it a "normal" executor from any flavour possible or if we get it from
That's an interesting question. |
|
Thank you for teaching me so much :) I think I'll leave the design of these two APIs to you, as you obviously know this area far better than I do. |
|
Oof ... I didn't mean to press myself into this project, just wanted to make some suggestions. But if you think that would be ok, it would be an honour to me :-) But then I'll have to think even more about it to make it clean and thoroughly test it. (And the knowledge of this area is only a few weeks old and partially stems from ChatGPT, but I am very interested in how all this async stuff works :-)) |
|
Only a few weeks? That's even more impressive.
My library, It should take fewer than 10 lines of code, and that's how I started learning how generators and coroutines work. (generators and coroutines are almost the same). (Sorry for the late reply. I can read English fairly quickly, but writing it takes me much longer.) |
run_in_thread() and run_in_executor() start their job and then go into a polling mode where they check the "done" flag in a regular fashion.
This is not very elegant, considering the fact that we have beautiful event classes at hand which are much better to be used for waiting.