实验运行调度管理器
Prepper 类是 Quatm 实验调度与运行系统的核心组件,负责管理实验队列、线程调度和状态跟踪。概述
Prepper 类(位于 quatm.gui.prepper 模块)是实验调度和运行系统的核心,提供以下核心能力:
- 任务队列管理:维护待执行的实验任务列表
- 线程调度:基于线程池的单线程调度策略,避免并发冲突
- 状态跟踪:通过
expDict追踪每个实验的配置和运行状态 - 定时轮询:周期性检查任务状态并更新 UI
核心架构
graph TD
A[实验任务入队] --> B[queue 任务队列]
B --> C[threadpool 线程池]
C --> D[执行实验]
D --> E[expDict 状态更新]
E --> F[timer 定时刷新 UI]
F --> G[browser 界面展示]API 参考
构造函数
from quatm.gui.prepper import Prepper
prepper = Prepper(browser=None)
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
browser | object | 否 | 浏览器/UI 对象,用于界面交互和状态展示 |
成员变量
| 变量 | 类型 | 说明 |
|---|---|---|
browser | object | 关联的 UI 浏览器对象 |
queue | Queue | 实验任务队列(FIFO) |
expDict | dict | 实验配置与状态字典 |
threadpool | ThreadPoolExecutor | 线程池(max_workers=1) |
timer | QTimer | UI 定时刷新器 |
使用示例
基础用法
from quatm.gui.prepper import Prepper
from quatm.experiments import RabiExperiment
# 1. 初始化调度器
prepper = Prepper(browser=my_browser)
# 2. 创建实验并加入队列
exp = RabiExperiment(
qubit="q0",
durations=[10, 20, 50, 100], # ns
amplitudes=[0.1, 0.2, 0.3, 0.4]
)
prepper.queue.put(exp)
# 3. 启动调度(从队列中取出并执行)
prepper.start()
批量实验调度
# 批量提交多个实验
experiments = [
RabiExperiment(qubit="q0", durations=range(10, 100, 10)),
RamseyExperiment(qubit="q0", delays=range(0, 1000, 50)),
T1Experiment(qubit="q0", wait_times=range(1, 100, 5)),
]
for exp in experiments:
prepper.queue.put(exp)
# 调度器会按 FIFO 顺序逐个执行
prepper.start()
线程模型
Prepper 使用 max_workers=1 的线程池设计,原因如下:
- 硬件安全:避免多个实验同时操作同一 FPGA 控制器,防止寄存器冲突
- 状态一致性:确保
expDict在单线程下读写安全,无需加锁 - 可预测性:实验按入队顺序严格串行执行,结果可复现
from concurrent.futures import ThreadPoolExecutor
# Prepper 内部等价于:
self.threadpool = ThreadPoolExecutor(max_workers=1)
错误处理
调度器内置了异常捕获机制,通过 traceback 模块记录详细的堆栈信息:
import traceback
def _run_experiment(self, exp):
try:
result = exp.run()
self.expDict[exp.id] = {"status": "done", "result": result}
except Exception as e:
self.expDict[exp.id] = {
"status": "error",
"error": str(e),
"traceback": traceback.format_exc()
}
实验失败不会中断调度器——错误被记录在 expDict 中,后续任务继续执行。
扩展指南
添加调度策略
如需支持优先级调度或依赖调度,可以扩展 Prepper 类:
class PriorityPrepper(Prepper):
"""支持优先级调度的实验管理器"""
def __init__(self, browser=None):
super().__init__(browser)
from queue import PriorityQueue
self.queue = PriorityQueue()
def submit(self, exp, priority=0):
"""提交实验并指定优先级(数值越小优先级越高)"""
self.queue.put((priority, exp))
添加实验类型
通过实现统一的实验接口,Prepper 可以支持任意实验类型:
class BaseExperiment:
"""所有实验的基类"""
def run(self):
raise NotImplementedError
@property
def id(self):
return id(self)
# Prepper 通过鸭子类型支持任何实现了 run() 方法的对象
常见问题
Q: 为什么线程池大小固定为 1? A: 量子物理实验中,多个实验同时操作同一硬件可能导致不可预料的结果。单线程模型保证了时序确定性。
Q: 如何查看当前队列中的任务?
A: 通过 prepper.queue.qsize() 获取待执行任务数,通过 prepper.expDict 查看各实验状态。
Q: 实验执行中可以暂停吗? A: 任何进程或者子进程都可以在实验执行过程中随时暂停、编辑、删除和添加。