在阻塞脚本的线程中循环

Loop in Thread that blocks the Script

我遇到了一个我不知道如何解决的问题。可能解决方案也很简单,但目前它并没有出现在我的脑海中。啊,我不知道标题要写什么,所以如果你想改变你认为合法的方式,那就去做吧=)

我放了一个简化版的代码,出现问题的地方:

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()

在说问题之前,先说明一下我的意图。我的想法是创建一个 class 平行于负责加载所有使用资源的主程序。与此同时,它必须 "dialogue" 与主 class 并修改它的一个变量来显示上传进度。前段时间我在 Whosebug 上问了一个关于类似问题的类似问题 (Link Question)。不同之处在于,在那个问题中,并行函数在主 class 内部。但是考虑到要加载的资源量,我决定单独为他提供一个 class。一切都写完后,我想到了另一个问题。虽然是后来写的,但是Thread在window出现之前就已经启动了。我想到用几秒钟添加一个简单的 time.sleep 集。但后来我推断可能是因为用户过度使用RAM导致延迟,因此设置的时间不够。所以我修改了,添加了一个 while 循环,条件是如果 window 是可见的,它会结束循环并继续加载,否则它会等待一秒钟。在这里,我们终于遇到了问题。编写的脚本不起作用。或者更确切地说,尽管它在线程中打开,但它仍然停留在循环中。从我之前的问题中,我知道 Thread 不应该直接接触 Pyglet,事实上它不会发生,因为它只是读取变量的状态。所以我不明白为什么我会得到这个结果。该循环似乎不是并行发生的,因此阻止了 on_show 函数,该函数无法更新变量并因此中断了循环。你对我解决我遇到的问题有什么建议吗?感谢您的帮助

而不是在这一行传递对 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")
    // ...