我有一个脚本,可以将 UDP 缓冲区发送到微控制器来控制 LED。我使用 matplotlib 绘制和“模拟”这些 LED,并且还可以在 FunAnimation 回调中发送 UDP 缓冲区。
当在 FuncAnimation Timer 回调中发送 udp 数据包时,可以顺利、及时地接收该数据包。当使用 python 事件循环、线程或简单的睡眠/while 循环时,它是不一致且不稳定的。
这是 matplotlib FunAnimation 代码的编辑示例(效果很好):
# matplotlib use case
def update(_):
send_udp_buffer()
return scat # scatter plot of LEDs
ani = animation.FuncAnimation(
fig=fig,
func=update,
frames=60,
interval=50, # 50 milliseconds
)
这是我尝试过的基于通用 while 循环的代码的示例(最终结果不稳定且不一致):
# Standard while-loop
while True:
send_udp_buffer()
time.sleep(.05)
# python event-loop
import asyncio
async def periodic():
while True:
send_udp_buffer()
await asyncio.sleep(0.05)
loop = asyncio.new_event_loop()
asyncio.set_event_loop(loop)
task = loop.create_task(periodic())
我使用的是 MacOSX,所以 FuncAnimation 使用的 Timer 是 TimerMac,它是 NSTimer 的包装。我尝试过包含并利用它,但似乎存在一些隐藏的实现细节。
为什么事件循环的行为方式与 matplotlib 计时器不同,我如何复制这种行为?
对于任何好奇的人,我找到了答案。
我的假设是错误的,FuncAnimation 并不比其他方法更好或更流畅。 FuncAnimation 实际上并不使用提供给它的间隔。它保持在100ms左右。由于 UDP 数据包之间的延迟,FuncAnimation 看起来更好,所以我的 50 毫秒延迟太激进了。
但是,如果有人对在 python 中使用 NSTimer 感到好奇,有一个包装 obj-c 类的库,
pyobjc