Задать вопрос
@allresize

Как асинхронно использовать gui и несколько бесконечных циклов?

Внутри моей программы работают около 30- бесконечных async функций. Все эти функции запускаются методом loop.gather().
Прошу привести пример кода как правильно встроить сюда интерфейс. Во всех библиотеках которые я рассмотрел, для запуска gui используется какой-нибудь start_main_loop, который блокирует выполнение моих async функций.
  • Вопрос задан
  • 541 просмотр
Подписаться 1 Средний Комментировать
Решения вопроса 1
sergey-gornostaev
@sergey-gornostaev Куратор тега Python
Седой и строгий
Асинхронный код запустить в отдельном потоке, а все взаимодействия с интерфейсом из этого кода делать сигналами. Есть ещё библиотеки, позволяющие использовать цикл событий asyncio в качестве цикла событий окна, что звучит здорово, но сам я их в бою не пробовал.

UPDATE:
Надо же, с 2019-го многое поменялось в интересную сторону. Для PyQt и PySide есть qasync, который активно развивается, а для Tk вообще не нужны сторонние библиотеки:
import tkinter as tk
from tkinter import ttk
import asyncio


class App:
    async def exec(self):
        self.window = Window(asyncio.get_event_loop())
        await self.window.show();


class Window(tk.Tk):
    def __init__(self, loop):
        self.loop = loop
        self.root = tk.Tk()
        self.animation = "░▒▒▒▒▒"
        self.label = tk.Label(text="")
        self.label.grid(row=0, columnspan=2, padx=(8, 8), pady=(16, 0))
        self.progressbar = ttk.Progressbar(length=280)
        self.progressbar.grid(row=1, columnspan=2, padx=(8, 8), pady=(16, 0))
        button_block = tk.Button(text="Calculate Sync", width=10, command=self.calculate_sync)
        button_block.grid(row=2, column=0, sticky=tk.W, padx=8, pady=8)
        button_non_block = tk.Button(text="Calculate Async", width=10, command=lambda: self.loop.create_task(self.calculate_async()))
        button_non_block.grid(row=2, column=1, sticky=tk.W, padx=8, pady=8)

    async def show(self):
        while True:
            self.label["text"] = self.animation
            self.animation = self.animation[1:] + self.animation[0]
            self.root.update()
            await asyncio.sleep(.1)

    def calculate_sync(self):
        max = 3000000
        for i in range(1, max):
            self.progressbar["value"] = i / max * 100

    async def calculate_async(self):
        max = 3000000
        for i in range(1, max):
            self.progressbar["value"] = i / max * 100
            if i % 1000 == 0:
                await asyncio.sleep(0)


asyncio.run(App().exec())
Ответ написан
Комментировать
Пригласить эксперта
Ответы на вопрос 1
AshBlade
@AshBlade
Просто хочу быть счастливым
Для такого нужно запускать отдельные потоки.
Во всех GUI приложениях всегда есть один главный поток, который используется для обработки пользовательского ввода (и только). Для фоновых работ надо использовать фоновые потоки. async/await в данном случае не подходит
Ответ написан
Комментировать
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы