tkinter MP working like a charm

Terry Reedy tjreedy at udel.edu
Sun Dec 31 20:52:41 EST 2017


On 12/30/2017 7:57 PM, Wu Xi wrote:
> from tkinter import *                                    #    I cant see anything wrong with this , it works like a charm

This imports about 200 names.  A reader may not know which names are 
builtins and which are imports.  There may also be accidental name 
conflicts.

> from tkinter import messagebox                           #    is there a serious concern doing things his way ?

This is the normal way to import tkinter subpackages.

> import asyncio , threading ,  random                     #    goal is multi tasking with the GUI not freezing before loop completed
>   							 #    which is being achieved here !

I verified that this works in 3.7.0a3 as I believe you intend.  So it is 
possible to create and run a tk loop in the main thread and run async 
loop (created in the main thread) in a subthread.  I don't think anyone 
knows when this will and will not work.

What you show below is that asyncio.sleep and asyncio.wait work under 
this circumstance.  Actually fetching even one url and making it 
readable from the main thread, so it can be displayed in a tk Text 
widget, would be even more impressive, and useful.

> def _asyncio_thread(async_loop):
>      async_loop.run_until_complete(do_urls())
> 
> def do_work(async_loop):
>      """ Button-Event-Handler starting stuff """
>      threading.Thread(target=_asyncio_thread, args=(async_loop,)).start()
> 
> async def one_url(url):
>      """ One task. """
>      sec = random.randint(1, 8)
>      await asyncio.sleep(sec  )
>      return 'url: {}  ---  sec: {}'.format(url, sec)
> 
> async def do_urls():
>      """ Creating and starting 10 tasks.         """
>      tasks   = [one_url(url)  for url  in range(10)]
>      completed, pending =  await asyncio.wait(tasks)
>      results = [task.result() for task in completed]
>      print('\n'.join(results))
> 
> def do_nofreeze():
>      messagebox.showinfo(message='see, Tkinter is still responsive')
> 
> def submain(async_loop):
>      root = Tk()
>      b1 = Button(master=root, text='do work',       command= lambda:do_work( async_loop)).pack()
>      b2 = Button(master=root, text='Frozen?',       command=do_nofreeze                 ).pack()

.pack() returns None, and binding None to b1 and b2 is useless.  Either 
skip the assignment or call .pack after the assignment.

Button(master=root, text='do work',
        command= lambda:do_work( async_loop)).pack()

b1 = Button(master=root, text='do work',
             command= lambda:do_work( async_loop))
b1.pack()

Since b1 and b2 here are local variables not accessible output submain, 
do the former.  If submain were a method, 'self.b1 = Button...' would 
make it easy to access the button from elsewhere, as for testing.  (It 
is also possible to introspect root for its contents.)

>      root.mainloop()
> 
> if __name__ == '__main__':
>      async_loop = asyncio.get_event_loop()    #  all in this loop
>      submain(async_loop)

To do everything in the main thread, one can replace 'root.mainloop' 
with loop.run_forever (in the main thread) and repeated root.update calls.

-- 
Terry Jan Reedy




More information about the Python-list mailing list