线程中的循环阻塞了脚本。

3
我遇到一个问题,无法想出解决方法。可能解决方法也很简单,但目前我的头脑中没有出现。啊,我不知道在标题中写什么,所以如果您想更改它是合法的,请随意更改 =)
我放了一个简化版本的代码,在那里出现了问题:
from pyglet.gl import *
import threading, time, os

FPS = 120.0

class ucgm(pyglet.window.Window):

    window_on_show = False
    grid_set = 32, 18
    old_set = 1024, 576
    new_set = old_set

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.__video_set()

        self.__resource = Resource_Load(self)
        s_l = threading.Thread(target=self.__resource.start_load())
        s_l.start()

    def on_show(self):
        print("1")
        self.window_on_show = True
        print("2")

    def on_draw(self):
        self.clear()

    def update(self, dt):
        pass

    def on_close(self):
        os._exit(0)

    def __video_set(self):
        self.__platform = pyglet.window.get_platform()
        self.__default_display = self.__platform.get_default_display()
        self.__default_screen = self.__default_display.get_default_screen()

        self.set_size(self.new_set[0], self.new_set[1])
        self.location = self.__default_screen.width // 2 - self.new_set[0] // 2, self.__default_screen.height // 2 - self.new_set[1] // 2
        self.set_location(self.location[0], self.location[1])

class Resource_Load():

    def __init__(self, main):
        self.engine = main
        self.loop_load = True

    def start_load(self):
        while self.loop_load:
            if self.engine.window_on_show:
                self.loop_load = False
                print("3")
            else:
                print("4")
                time.sleep(1)
        print("5")

if __name__ == "__main__":
    uc = ucgm()
    pyglet.clock.schedule_interval(uc.update, 1 / FPS)
    pyglet.app.run()

谈到这个问题之前,我想解释一下我的意图。我的想法是创建一个与主类并行的类,负责加载所有使用的资源。同时,它必须与主类“对话”,修改一个变量,显示上传进度。不久前,我在Stackoverflow上问了一个类似的问题(Link Question)。不同之处在于,在那个问题中,平行函数是内部的。但考虑到要加载的资源数量,我决定为他专门配备一个单独的类。一切都写好后,我想到了另一个问题。尽管它是后来写的,线程却在窗口完全出现之前就启动了。我想添加一个简单的time.sleep,设置几秒钟。但后来我想到,由于用户过度使用RAM可能会导致延迟,因此设置的时间不足。所以我进行了修改,添加了一个带有条件的while循环,如果窗口可见,它将结束循环并继续加载,否则它将等待一秒钟。最后我们终于遇到了问题。脚本按照其编写方式无法工作。或者说,尽管它在一个线程中打开,但它仍然被卡在循环中。从我的先前的问题中,我知道线程不应直接触摸Pyglet,实际上它没有发生,因为它只读取一个变量的状态。所以我不明白为什么会得到这个结果。循环似乎并行不发生,因此阻止了on_show函数无法更新变量,从而打破了循环。你有什么建议可以帮助我解决我遇到的问题吗?谢谢你的帮助。
1个回答

1

在这一行中,不要传递对start_load函数的引用:

s_l = threading.Thread(target=self.__resource.start_load())

那行代码实际上是在调用该函数(注意()),这将在主线程上运行该无限循环。去掉那个(); threading.Thread会为您调用它:

s_l = threading.Thread(target=self.__resource.start_load)

此外,在一个线程中等待另一个线程发生某些事情的更好方法是使用Python提供的线程同步对象之一,例如threading.Event
class ucgm(pyglet.window.Window):
    window_opened = threading.Event()
    // ...
    def on_show(self):
        self.window_opened.set()
    // ...

class Resource_Load():
    // ...
    def start_load(self):
        self.engine.window_opened.wait()
        print("done")
    // ...

该死,我真的没有注意到我添加了括号。谢谢你的帮助。我只有一个问题,对于“线程”,您是否需要每次创建一个新的“threading.Event()”,还是只需创建一次? - BlackFenix06
我不是很清楚你的意思。您只需为要等待的每个事件创建一个事件。如果您有多个线程,但它们都在等待父线程中设置的相同事件,则只需要在父线程中创建一个事件。如果您有多个线程正在等待不同的事情,则将有多个事件。我喜欢将这些事件视为红色交通灯。调用.wait()的任何线程都会等待它,而调用.set()的线程会将其更改为绿色。 - Jacob

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接