Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

add_background_task is blocked in this Situation! #2720

Closed
vzool opened this issue Jul 21, 2024 · 1 comment
Closed

add_background_task is blocked in this Situation! #2720

vzool opened this issue Jul 21, 2024 · 1 comment
Labels
bug A crash or error in behavior.

Comments

@vzool
Copy link

vzool commented Jul 21, 2024

Describe the bug

I made a loading page that works fine, but when I start using it with something, the whole UI gets blocked and stopped react until the background process finishes.

Steps to reproduce

import toga
from toga.style import Pack
from toga.style.pack import COLUMN, ROW

from zakat import ZakatTracker # pip install zakat
from time import time_ns
import asyncio

class BackgoundTasks(toga.App):
    def startup(self):
        self.main_box = toga.Box(style=Pack(direction=COLUMN))
        async def generate_records(widget, **kwargs):
            print('generate_records')
            self.goto_loading_page(widget)
            await asyncio.sleep(0.6)
            async def process(app, /, **kwargs):
                print('process')
                ZakatTracker.generate_random_csv_file('million.csv', count=1_000_000, with_rate=True) # very long process
                self.main_window.info_dialog(
                    'Message Status',
                    'Operation Accomplished Successfully',
                )
                self.goto_main_page(widget)
            self.add_background_task(process)
        self.main_box.add(toga.Button('Test Loading Page (Working Fine)', on_press=lambda e: self.goto_loading_page(e, True), style=Pack(flex=1)))
        self.main_box.add(toga.Button('Generate 1,000,000 record (UI Blocked!!!)', on_press=generate_records, style=Pack(flex=1)))
        self.main_window = toga.MainWindow(title=self.formal_name)
        self.main_window.content = self.main_box
        self.main_window.show()
    
    def goto_main_page(self, widget):
        self.main_window.content = self.main_box

    def goto_loading_page(self, widget, show_back_button=False):
        self.main_window.content = self.loading_page(widget, show_back_button)

    def loading_page(self, widget, show_back_button=False):
        print('loading_page')
        page = toga.Box(style=Pack(direction=COLUMN, flex=1, padding=(150,0)))
        animation_label = toga.Label('', style=Pack(flex=1, text_align='center', font_weight='bold', font_size=60))
        page_label = toga.Label('Loading', style=Pack(flex=1, text_align='center', font_weight='bold', font_size=21))
        timer_label = toga.Label('', style=Pack(flex=1, text_align='center', font_weight='bold', font_size=12))
        page.add(animation_label)
        page.add(page_label)
        page.add(timer_label)
        if show_back_button:
            page.add(toga.Button('Back', on_press=self.goto_main_page, style=Pack(flex=1)))
        # loading_animation
        text = ["◑", "◒", "◐", "◓"] # REF https://github.com/jaywcjlove/loading-cli
        animation_label.text = text[0]
        async def loading_animation(widget, **kwargs):
            print('loading_animation')
            i = 0
            while self.main_window.content == page:
                print('loading_animation', i)
                animation_label.text = text[i]
                i += 1
                if i >= len(text):
                    i = 0
                await asyncio.sleep(0.3)
        # timer
        start = time_ns()
        coloned_time, _ = ZakatTracker.duration_from_nanoseconds(time_ns() - start)
        timer_label.text = coloned_time
        async def timer(widget, **kwargs):
            print('timeer')
            while self.main_window.content == page:
                coloned_time, _ = ZakatTracker.duration_from_nanoseconds(time_ns() - start)
                timer_label.text = coloned_time
                await asyncio.sleep(0.1)
        self.add_background_task(loading_animation)
        self.add_background_task(timer)
        return page

def main():
    return BackgoundTasks()

Expected behavior

The UI should behave smoothly in all situations when using add_background_task.

Screenshots

Screen.Recording.1446-01-15.at.1.31.38.PM.mov

Environment

  • Operating System: macOS 14.5 (23F79)
  • Python version: 3.11.5
  • Software versions:
    • Briefcase: 0.3.19
    • Toga: 0.4.5

Logs


Additional context

No response

@vzool vzool added the bug A crash or error in behavior. label Jul 21, 2024
@mhsmith
Copy link
Member

mhsmith commented Jul 21, 2024

add_background_task is a misleading name, which is why we're deprecating it in the next version of Toga (#2678). It doesn't actually create a background thread, so your user interface will still freeze unless the task calls await frequently enough.

If you need to run some slow code which doesn't call await frequently enough, you'll need to put it in a thread. See #2099 (comment) for examples.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug A crash or error in behavior.
Projects
None yet
Development

No branches or pull requests

2 participants