在阻塞脚本的线程中循环
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")
// ...
我遇到了一个我不知道如何解决的问题。可能解决方案也很简单,但目前它并没有出现在我的脑海中。啊,我不知道标题要写什么,所以如果你想改变你认为合法的方式,那就去做吧=)
我放了一个简化版的代码,出现问题的地方:
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")
// ...