Я создаю клиент API обмена криптовалютами, используя Python3.5 и Tkinter. У меня есть несколько дисплеев, которые я хочу обновлять асинхронно каждые 10 секунд. Я могу обновлять дисплеи каждые 10 секунд, используя Tk.after()
, как в этом примере
def updateLoans():
offers = dd.loanOffers()
demands = dd.loanDemands()
w.LoanOfferView.delete(1.0, END)
w.LoanDemandView.delete(1.0, END)
w.LoanOfferView.insert(END, offers)
w.LoanDemandView.insert(END, demands)
print('loans refreshed') root.after(10000, updateLoans)
Для продолжения использования метода after
для обновления непрерывно каждые 10 секунд функция updateLoans()
должна быть передана как вызываемая в after()
внутри функции.
Теперь часть, которая меня точит, когда я делаю эту функцию асинхронной с новым асинхронным python и ожидаю ключевые слова
async def updateLoans():
offers = await dd.loanOffers()
demands = await dd.loanDemands()
w.LoanOfferView.delete(1.0, END)
w.LoanDemandView.delete(1.0, END)
w.LoanOfferView.insert(END, offers)
w.LoanDemandView.insert(END, demands)
print('loans refreshed') root.after(10000, updateLoans)
Проблема заключается в том, что я не могу ждать вызываемой внутри параметров для after
метод. Поэтому я получаю предупреждение о времени выполнения. RuntimeWarning: coroutine 'updateLoans' was never awaited
.
Мой начальный вызов функции IS помещается внутри цикла события.
loop = asyncio.get_event_loop()
loop.run_until_complete(updateLoans())
loop.close()
Дисплей сначала заполняется, но никогда не обновляется.
Как я могу использовать Tk.after
для непрерывного обновления отображения tkinter асинхронно?
tk.after
принимает нормальную функцию, а не сопрограмму. Чтобы выполнить сопрограмму до завершения, вы можете использоватьrun_until_complete
, как вы делали это в первый раз:Кроме того, не вызывайте
loop.close()
, поскольку вам снова понадобится цикл.Приведенное выше быстрое исправление отлично подойдет для многих случаев использования. Однако дело в том, что графический интерфейс будет полностью не отвечать, если
updateLoans()
занимает много времени из-за медленной сети или проблемы с удаленным сервисом. Хорошее приложение с графическим интерфейсом захочет избежать этого.Хотя Tkinter и asyncio пока не могут совместно использовать цикл событий, вполне возможно запустить цикл событий asyncio в отдельном потоке. Затем основной поток запускает графический интерфейс, а выделенный поток asyncio - все сопрограммы asyncio. Когда цикл обработки событий должен уведомить графический интерфейс для обновления чего-либо, он может использовать очередь, как показано здесь. С другой стороны, если GUI необходимо сообщить циклу событий что-то сделать, он может вызвать
call_soon_threadsafe
илиrun_coroutine_threadsafe
.Пример кода (не проверено):
RuntimeError: There is no current event loop in thread 'Thread-1'