为什么 Kivy UrlRequest 回调会阻塞 GUI 线程?

问题描述 投票:0回答:1

我有 Kivy 应用程序,屏幕上有一个下载按钮,可以下载和处理各种远程数据表。一切都工作得很好,但 gui 在该过程中被阻止,正如 MDSpinner 所证明的那样,该 MDSpinner 在下载过程完全完成之前冻结了大约一半。

整个深度学习进程正在另一个不接触 GUI 的线程中运行,因此这种情况不会发生。

我的故障排除发现 UrlRequest 回调正在执行阻塞。即使回调中的简单睡眠也会挂起 GUI!

知道为什么吗?我需要在另一个线程中运行回调吗?

由于实际代码非常复杂,这里有一些简单的伪代码来演示问题。

from kivy.network.urlrequest import UrlRequest
from functools import partial
from kivy.clock import Clock, mainthread
from threading import Thread
from kivymd.uix.screen import MDScreen 
import time

class myScreen(MDScreen):

    def on_button(self):
        # activate spinner when download button pressed
        self.ids.spinner.active = True
    
        # run sync stuff in new thread
        t = Thread(target=self.sync_thread)
        t.start()


    def sync_thread(self):
        # lots of code here including several async downloads like this:
        download(some_url)
        
        # when all downloads are done, kill spinner
        self.kill_spinner()
        
        
    @mainthread
    def kill_spinner(self):
        # uses decorator to set gui widget from another thread
        self.ids.spinner.active = False


# URLRequest code -----------------------------
def download(self, url):
    cb = partial(mycallback, arg)
    UrlRequest(url=url, req_headers=myconfig.headers, timeout=timeout, on_success=cb, on_error=cb, on_failure=cb)


def mycallback(self, arg):
    # used to process data from each download
    # PROBLEM LIES HERE!  Anything here - even a simple sleep will hang spinner(gui) until finished
    time.sleep(5)
kivy kivy-language
1个回答
0
投票

我认为你应该在on_button函数中调用kill_spinner函数。在这里,即使您在这里有一个线程,您也会在下载并处理导致滞后的所有内容后禁用微调器。

from kivy.network.urlrequest import UrlRequest
from functools import partial
from kivy.clock import Clock, mainthread
from threading import Thread
from kivymd.uix.screen import MDScreen 
import time

class myScreen(MDScreen):

    def on_button(self):
        # activate spinner when download button pressed
        self.ids.spinner.active = True
    
        # run sync stuff in new thread
        t = Thread(target=self.sync_thread)
        t.start()
        # when all downloads are launched, kill spinner
        self.kill_spinner()


    def sync_thread(self):
        # lots of code here including several async downloads like this:
        download(some_url)
        
    @mainthread # should be useless
    def kill_spinner(self):
        # uses decorator to set gui widget from another thread
        self.ids.spinner.active = False


# URLRequest code -----------------------------
def download(self, url):
    cb = partial(mycallback, arg)
    UrlRequest(url=url, req_headers=myconfig.headers, timeout=timeout, on_success=cb, on_error=cb, on_failure=cb)


def mycallback(self, arg):
    # used to process data from each download
    # PROBLEM LIES HERE!  Anything here - even a simple sleep will hang spinner(gui) until finished
    time.sleep(5)
© www.soinside.com 2019 - 2024. All rights reserved.