跳转至

ADR-002: 采用多阶段流水线并行架构重构导出功能

状态

已接受 (Accepted)

背景 (Context)

本应用的核心功能是将大量电子元件(符号、封装、3D模型)从远程服务器导出为本地 KiCad 库文件。目前的导出过程是串行的,当用户选择批量导出时,需要等待非常长的时间,用户体验极差。为了显著提升应用性能、压榨硬件能力并改善用户体验,我们需要设计一套全新的高性能并行处理架构。此架构还必须能够支持精确实时的进度反馈和详细的导出成功/失败统计。

决策 (Decision)

我们将采用多阶段流水线并行 (Multi-Stage Pipeline Parallelism) 架构来重构整个导出服务。该架构将工作流分解为三个独立的、可并发执行的阶段:

  1. 抓取阶段 (Fetch Stage): 使用一个专门的、大规模的I/O密集型线程池,通过异步网络请求并发下载所有元件的原始数据。

  2. 处理阶段 (Process Stage): 使用一个专门的、规模与CPU核心数匹配的CPU密集型线程池,并发地解析原始数据,并将其转换为结构化的KiCad数据对象。

  3. 写入阶段 (Write Stage): 使用一个专门的I/O线程池,将处理好的数据对象写入到磁盘。对于符号库(.kicad_sym),将先写入独立的临时文件。

各阶段之间通过线程安全的有界队列进行数据传递,实现任务的解耦和高效流转。ExportService 将作为整个流水线的调度中心,负责初始化、监控状态,并在所有任务完成后,执行一个最终的"合并符号库临时文件"步骤。

状态反馈将通过定义良好的数据结构 ComponentExportStatus 来实现,它在流经流水线的过程中被逐步填充,最终由写入阶段反馈给 ExportService 进行聚合,用于精确计算总体进度和生成详细统计。

后果 (Consequences)

正面影响

  • 极致的性能: 通过最大化地重叠网络I/O、CPU计算和磁盘I/O,实现了极高的并发度,能充分利用多核CPU和高速网络/磁盘。

  • 资源高效: 为不同类型的任务(I/O密集 vs CPU密集)配置了最优的线程池,避免了资源浪费。

  • 精准的诊断与反馈: 架构能清晰地反映出瓶颈所在阶段,并能提供详尽的失败原因(例如,是下载失败还是数据解析失败)。

  • 强大的可扩展性: 未来增加新的处理步骤(如DRC检查)只需在流水线中增加一个新阶段即可。

负面影响

  • 复杂性增加: 相比简单的串行或并行模型,流水线架构在代码实现和逻辑上都更为复杂,需要精心管理线程、队列和状态。

  • 调试难度提高: 诊断多线程环境下的竞态条件或死锁等问题将比单线程更加困难。

  • 代码量增多: 需要定义更多的工作单元(Workers)、数据结构和管理类。

考虑过的其他方案

1. 元件级并行模型 (一线程一元件)

  • 描述: 为每个需要导出的元件创建一个独立的任务,并交由一个统一的线程池来执行。

  • 放弃原因: 虽然比串行模型有巨大提升,但效率并非最优。它没有区分I/O和CPU密集型任务,导致线程池配置无法最优化。同时,它也无法实现不同元件在不同处理阶段的"任务重叠",未能达到极致性能的目标。

2. 带文件锁的元件级并行模型

  • 描述: 在"一线程一元件"模型的基础上,在写入符号库(共享文件)时使用全局互斥锁。

  • 放弃原因: 互斥锁会成为严重的性能瓶颈,导致所有线程在写入符号时必须排队等待,使这一关键步骤退化为串行,严重削弱了并行的效果。

实现细节

线程池配置

  • Fetch Stage: 32个线程(I/O密集型,可配置)
  • Process Stage: CPU核心数(CPU密集型,与CPU数量匹配)
  • Write Stage: 8个线程(磁盘I/O密集型,可配置)

核心组件

  1. BoundedThreadSafeQueue: 线程安全的有界队列,用于阶段间数据传递
  2. ComponentExportStatus: 跟踪每个元件在各阶段的执行状态
  3. FetchWorker: 负责网络数据下载
  4. ProcessWorker: 负责数据解析和转换
  5. WriteWorker: 负责文件写入
  6. ExportServicePipeline: 流水线调度中心

进度计算

  • Fetch阶段: 30%权重
  • Process阶段: 50%权重
  • Write阶段: 20%权重

总进度 = (Fetch进度 × 30 + Process进度 × 50 + Write进度 × 20) / 100

参考资料