运行方式
当前线程、后台线程与手动 update 三种运行方式。
运行方式
本章只适用于需要持续计算 SDK 处理后的数据或使用自动重连等后台功能的程序。只读取原始 pose/IMU 时不需要选择运行方式,见 数据来源与读取方式;需要上述功能时再往下读。
需要上述功能时,通过 Glove 选择一种运行方式。同一次运行中不要混用:
- 命令行程序通常调用
glove.run_forever(),在当前线程持续运行; - GUI、异步程序或当前线程还要处理其他工作时,可以调用
glove.run_background()在后台运行; - 已有同步主循环时,可以持续调用
glove.update(),由程序控制调度。
当前线程持续运行
glove.run_forever()run_forever() 阻塞当前线程,直到收到停止请求或 SDK 因错误停止。公开命令行示例按
Ctrl+C 结束进程;需要主动停止时,使用后台模式。
后台线程运行
glove.run_background()
try:
...
finally:
glove.request_stop()
glove.join()join() 不只是等待线程结束,也负责把后台运行错误报告给调用方,因此不能只调用
request_stop() 而省略 join()。后台模式适用于 GUI 主线程、宿主事件循环或其他不能阻塞当前线程的场景。
普通 asyncio 程序读取 SDK 处理后的数据时,通常在 start() 后调用 glove.run_background(),再通过 await output.next() 或 async for 读取输出。asyncio event loop 本身不会推进 SDK 调度,SDK 后台运行和 event loop 都需要保持运行。close() 可能等待数据处理与 callback 清理,异步程序中建议通过 asyncio.to_thread() 调用。
如果外部帧来自 async iterator,应创建一个独立的 asyncio task 持续调用 push_frame(),同时通过 await output.next() 或 async for 读取输出。只等待输出而不继续提交输入帧,不会产生新的 SDK 处理后的数据。
手动 update
手动模式适合已有同步主循环并希望主动控制 SDK 调度的程序。先订阅 SDK 处理后的数据,再启动设备;每次调用
glove.update() 都会计算到期的任务,也可以通过 latest() 立即读取当前输出:
output = glove.device().output()
output.subscribe(on_output)
glove.start()
for _ in range(100):
update = glove.update()
latest = output.latest()
if latest is not None:
print(latest.sequence, latest.value)
if update.has_next_task:
update.sleep()按用途选择字段:
| 想做什么 | 读取字段 |
|---|---|
| 记录已推进的调度次数 | tick |
| 观察本次执行了多少任务 | ran_task_count |
| 决定是否继续等待下一项任务 | has_next_task |
| 等下一项任务到期再继续 | sleep() |
完整字段、类型和返回值见 UpdateResult。sleep() 返回
SleepResult.READY、STOPPED 或 NO_TASKS。每个 UpdateResult 只能等待一次;重复使用或在下一次更新后再使用会抛出 StaleUpdateError。
手动模式只改变 SDK 调度由谁推进,不改变数据读取方式。能够自行协调 SDK 调度与 asyncio event loop 的宿主也可以采用手动 update(),但必须保证持续调用 glove.update();只等待输出而不继续推进调度,不会产生新的 SDK 处理后的数据。普通异步程序优先使用 glove.run_background();异步读取方式见 异步读取。
完整异步流程见 async_runtime.py。