Главная проблема: у любого GUI-приложения есть бесконечный цикл обработки оконных сообщений. У любого асинхронного приложения есть бесконечный цикл-реактор, который обрабатывает реакции на завершение асинхронных операций (в т.ч. ввода-вывода). Это два разных цикла, они друг о друге не знают, и в одном потоке может работать только один из них.
Отсюда два решения.
1. Плюнуть на Tkinter и использовать PyQT. Есть сторонняя библиотека pyqt-async, которая вроде как позволяет засунуть обработку оконных сообщений в цикл-реактор.
2. Запустить в главном потоке цикл-реактор, а GUI (на базе любого фреймворка) создать и запустить во вспомогательном. Любые задачи для выполнения в главном потоке делать через
asyncio.run_coroutine_threadsafe(). Любые модификации GUI делать, создавая статичный объект-описание операции над GUI и поместив его в очередь (
Queue, например). Поток GUI должен периодически читать эту очередь, и вносить найденные там изменения. В ткинтере может помочь метод after(), наверно есть аналоги и в других фреймворках.