【问题标题】:Loop in Thread that blocks the Script在阻塞脚本的线程中循环
【发布时间】:2019-07-30 21:24:49
【问题描述】:

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

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

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 函数。您对我解决我遇到的问题有什么建议吗?感谢您的帮助

【问题讨论】:

    标签: python python-3.x multithreading python-3.7 pyglet


    【解决方案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")
        // ...
    

    【讨论】:

    • 该死,我并没有真正注意到我添加了括号。谢谢你的帮助。我只有一个问题,对于threads,你必须每次都创建一个新的threading.Event(),还是只创建一次?
    • 我不太清楚你的意思。您只需为要等待的每个事件创建一个。如果您有多个线程,但它们都在等待在父线程中设置的相同事件,您只需要在父线程中创建一个。如果您有多个线程在等待不同的事情,那么您将有多个事件。我喜欢把这些事件想象成一个红绿灯。任何调用.wait() 的线程都会等待,调用.set() 的线程会将其更改为绿色。
    猜你喜欢
    • 1970-01-01
    • 2019-11-15
    • 1970-01-01
    • 1970-01-01
    • 2018-10-27
    • 1970-01-01
    • 2014-10-26
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多