Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/361.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/cassandra/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python 如何使高频线程与低频更新的类对话? 总结_Python_Python Multithreading - Fatal编程技术网

Python 如何使高频线程与低频更新的类对话? 总结

Python 如何使高频线程与低频更新的类对话? 总结,python,python-multithreading,Python,Python Multithreading,我正在做一个实时物理模拟,需要一个低增量。我已将此模拟连接到python arcade游戏窗口,以实时显示信息 我为物理制作了一个单独的线程,因为在物理线程中有一些昂贵的矩阵乘法。然后,当更新完成时,我设置游戏窗口类的结果状态,游戏窗口可以在绘制新帧时显示这些状态 因此,我的想法是,game window类只需担心屏幕上的绘图,而物理线程负责所有计算 然而,在游戏窗口和线程之间的通信中存在瓶颈,我不知道是否有幕后洞察 我想做的事情的最小表示: 导入线程 导入时间 输入数学 进口拱廊 类Displ

我正在做一个实时物理模拟,需要一个低增量。我已将此模拟连接到python arcade游戏窗口,以实时显示信息

我为物理制作了一个单独的线程,因为在物理线程中有一些昂贵的矩阵乘法。然后,当更新完成时,我设置游戏窗口类的结果状态,游戏窗口可以在绘制新帧时显示这些状态

因此,我的想法是,game window类只需担心屏幕上的绘图,而物理线程负责所有计算

然而,在游戏窗口和线程之间的通信中存在瓶颈,我不知道是否有幕后洞察

我想做的事情的最小表示:
导入线程
导入时间
输入数学
进口拱廊
类DisplayWindow(arcade.Window):
定义初始化(自):
超级()
self.state=0
self.FPS=0
def设置_状态(自身、状态):
self.state=状态
def on_更新(自身、增量时间:浮动):
self.FPS=1./三角洲时间
def on_牵引(自):
arcade.start_render()
arcade.draw_text(f'FPS:{self.FPS:0.2f}',20,20,arcade.color.WHITE)
拱廊。绘制矩形填充(中心x=self.state*self.width,
中心y=自身高度/2,
颜色=拱廊。颜色。白色,
倾斜角度=0,
宽度=10,
高度=10)
#线程来模拟物理。
def模拟(显示):
t_0=时间。时间()
尽管如此:
#需要高频率的昂贵计算:
t=time.time()-t_0
x=数学sin(t)/2+0.5#用于演示的正弦曲线
#将其发送到显示窗口
显示。设置_状态(状态=x)
#时间。睡眠(0.1)#使用此选项运行更平稳
def main():
显示窗口=显示窗口()
物理线程=线程。线程(目标=模拟,参数=(显示窗口),守护进程=真)
物理_thread.start()
arcade.run()
返回0
如果uuuu name uuuuuu='\uuuuuuu main\uuuuuuu':
main()
预期结果:高帧速率下的平滑模拟。拱廊窗口只需以30或60 fps的速度运行on_draw。它只需要画一些东西

实际结果:物理循环运行速度极快,并调用FPS drops


当我将time.sleep(0.1)添加到物理线程中时,整个过程会变得更加平滑,我想出于某种原因,
set\u state(\u)
会减慢绘制循环。

Python线程可能不是您尝试执行的工作的理想工具

尽管人们可能会认为Python线程是并发运行的,但事实并非如此:全局解释器锁(GIL)只允许一个线程控制Python解释器

正因为如此,
arcade.Window
对象并没有及早获得控制Python解释器并运行其所有更新函数的机会,因为GIL在
物理线程的
模拟
函数中始终“关注”无限循环

在运行一定数量的指令或使用
time.sleep()
physics\u线程设置为sleep后,GIL只会释放对
physics\u线程的关注,并在其他线程上寻找其他操作。这正是您在经验上发现的恢复程序预期行为的方法

这是一个称为线程饥饿的典型问题的示例,可以使用。这会带来更大的复杂性,但会将CPU密集型计算和基于事件的轻量级接口分离到不同的进程中,从而解决您的问题。

多亏了,我考虑使用而不是

multiprocessing.Pipe
对象确保了双向通信,使整个过程更加顺畅。我现在还可以确保模拟的实时运行

在两侧的每个更新循环中,只需使用
send()
recv()
命令即可。尚未测试边缘案例,但似乎工作顺利

我在上面发布的示例中添加了修改:

导入时间
进口拱廊
从多处理导入进程,管道
从数学输入sin,pi
类DisplayWindow(arcade.Window):
def _初始__(自,连接:管道):
super().\uuuu init\uuuu(500500)
self.connection:Pipe=连接#多处理.Pipe
self.position:float=0#GUI显示状态
self.user_输入:float=1.0#模拟输入
self.FPS:float=0#帧/秒估计
def on_更新(自身、增量时间:浮动):
self.FPS=1./三角洲时间
#与仿真通信:
self.connection.send(self.user\u输入)
self.position=self.connection.recv()
def on_牵引(自):
arcade.start_render()
arcade.draw_text(f'FPS:{self.FPS:0.0f}',20,20,arcade.color.WHITE)
拱廊。绘制点(self.position,self.height/2,arcade.color.WHITE,10)
按键释放时的def(自身,符号:int,修饰符:int):
如果symbol==arcade.key.W:
self.user_输入=1.8
elif symbol==arcade.key.S:
self.user_输入=0.3
#模拟物理的单独过程目标:
def模拟(连接:管道):
t_0=时间。时间()
尽管如此:
freq=connection.recv()*2*pi#接收GUI用户输入
t=time.time()-t_0
x=sin(频率*t)*250+250
连接。发送(x)#将状态发送到GUI
def main():
父管道,子管道=管道()