2 回答

TA贡献1921条经验 获得超9个赞
Python 线程可能不是您尝试做的工作的理想工具。
尽管将 Python 线程视为并发运行可能很诱人,但事实并非如此:全局解释器锁 (GIL) 只允许一个线程控制 Python 解释器。更多信息
正因为如此,该arcade.Window
对象无法及早控制 Python 解释器并运行其所有更新函数,因为 GIL 始终“专注”simulation
于physics_thread
.
GIL 只会在physics_thread
运行一定数量的指令或使用which 在线程上执行physics_thread
设置为睡眠后才释放对 的关注并在其他线程上寻找其他事情要做。这正是您凭经验发现的恢复程序预期行为的方法。time.sleep()
这是一个称为线程饥饿的典型问题的示例,可以通过使用多处理库来解决。这会带来更多的复杂性,但会将您的 CPU 密集型计算和基于事件的轻量级接口分开在不同的进程中,从而解决您的问题。

TA贡献1789条经验 获得超8个赞
我研究了使用多处理而不是线程。
该multiprocessing.Pipe对象确保了双工通信并使整个事情变得更加顺畅。我现在还可以确保模拟的实时运行。
两边的每个更新循环,只需使用send()andrecv()命令。尚未测试边缘情况,但似乎工作顺利。
我将修改添加到上面发布的示例中:
import time
import arcade
from multiprocessing import Process, Pipe
from math import sin, pi
class DisplayWindow(arcade.Window):
def __init__(self, connection: Pipe):
super().__init__(500, 500)
self.connection: Pipe = connection # multiprocessing.Pipe
self.position: float = 0 # GUI Display state
self.user_input: float = 1.0 # Input to simulation
self.FPS: float = 0 # Frames per second estimation
def on_update(self, delta_time: float):
self.FPS = 1. / delta_time
# Communicate with simulation:
self.connection.send(self.user_input)
self.position = self.connection.recv()
def on_draw(self):
arcade.start_render()
arcade.draw_text(f'FPS: {self.FPS:0.0f}', 20, 20, arcade.color.WHITE)
arcade.draw_point(self.position, self.height/2, arcade.color.WHITE, 10)
def on_key_release(self, symbol: int, modifiers: int):
if symbol == arcade.key.W:
self.user_input = 1.8
elif symbol == arcade.key.S:
self.user_input = 0.3
# Separate Process target to simulate physics:
def simulation(connection: Pipe):
t_0 = time.time()
while True:
freq = connection.recv() * 2 * pi # Receive GUI user input
t = time.time() - t_0
x = sin(freq * t) * 250 + 250
connection.send(x) # Send state to GUI
def main():
parent_con, child_con = Pipe()
display_window = DisplayWindow(connection=parent_con)
physics = Process(target=simulation, args=(child_con,), daemon=True)
physics.start()
arcade.run()
physics.terminate()
return 0
if __name__ == '__main__':
main()
添加回答
举报