I want to use asyncio
in combination with a tkinter
GUI.
I am new to asyncio
and my understanding of it is not very detailed.
The example here starts 10 task when clicking on the first button. The task are just simulating work with a sleep()
for some seconds.
The example code is running fine with Python 3.6.4rc1
. But
the problem is that the GUI is freezed. When I press the first button and start the 10 asyncio-tasks I am not able to press the second button in the GUI until all tasks are done. The GUI should never freeze - that is my goal.
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
from tkinter import *
from tkinter import messagebox
import asyncio
import random
def do_freezed():
""" Button-Event-Handler to see if a button on GUI works. """
messagebox.showinfo(message='Tkinter is reacting.')
def do_tasks():
""" Button-Event-Handler starting the asyncio part. """
loop = asyncio.get_event_loop()
try:
loop.run_until_complete(do_urls())
finally:
loop.close()
async def one_url(url):
""" One task. """
sec = random.randint(1, 15)
await asyncio.sleep(sec)
return 'url: {}\tsec: {}'.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))
if __name__ == '__main__':
root = Tk()
buttonT = Button(master=root, text='Asyncio Tasks', command=do_tasks)
buttonT.pack()
buttonX = Button(master=root, text='Freezed???', command=do_freezed)
buttonX.pack()
root.mainloop()
A _side problem
...is that I am not able to run the task a second time because of this error.
Exception in Tkinter callback
Traceback (most recent call last):
File "/usr/lib/python3.6/tkinter/__init__.py", line 1699, in __call__
return self.func(*args)
File "./tk_simple.py", line 17, in do_tasks
loop.run_until_complete(do_urls())
File "/usr/lib/python3.6/asyncio/base_events.py", line 443, in run_until_complete
self._check_closed()
File "/usr/lib/python3.6/asyncio/base_events.py", line 357, in _check_closed
raise RuntimeError('Event loop is closed')
RuntimeError: Event loop is closed
Multithreading
Whould multithreading be a possible solution? Only two threads - each loop has it's own thread?
EDIT: After reviewing this question and the answers it is related to nearly all GUI libs (e.g. PygObject/Gtk, wxWidgets, Qt, ...).
url: 3 sec: 6
,url: 4 sec: 4
, etc. Perhaps you're encountering a bug that has been fixed (if you're using an earlier version of Python). – Greaseballcommand
/bind
). First problem is obvious - you stuck in the inner loop (asyncio
), while the outer loop in unreachable (tkinter
), hence GUI in unresponsive state. Second one - you already closedasyncio
loop. You either should close it once at the end (as @Terry proposed) or should create a new one each time. – Kersten