docs: 为全部13个源码模块和5个测试文件添加简体中文注释
- 每个文件补充模块级 docstring、类/函数 docstring、关键逻辑行内注释 - 注释风格:"中文说明" 或 # 中文说明 - 代码结构和逻辑完全不变
This commit is contained in:
@@ -1,3 +1,9 @@
|
||||
"""批量构建模块:支持并行或串行地处理多个独立换板打包任务。
|
||||
|
||||
提供 dataclass 用于封装单个构建任务、失败信息和批量结果,
|
||||
并包含工作进程数计算及并行/串行执行调度逻辑。
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import os
|
||||
@@ -8,39 +14,73 @@ from typing import Sequence
|
||||
from .builder import build_packed_3mf
|
||||
from .models import BuildOptions, BuildResult, PlateJob
|
||||
|
||||
# 独立批量构建的默认最大并行工作进程数
|
||||
INDIVIDUAL_BATCH_MAX_WORKERS = 8
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class IndividualBuildTask:
|
||||
"""单个独立构建任务,包含一个板作业和对应的构建选项。"""
|
||||
job: PlateJob
|
||||
"""要处理的板作业"""
|
||||
options: BuildOptions
|
||||
"""构建选项配置"""
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class IndividualBuildFailure:
|
||||
"""记录单个构建任务失败时的详细信息。"""
|
||||
index: int
|
||||
"""任务在原始列表中的索引"""
|
||||
job: PlateJob
|
||||
"""失败的板作业"""
|
||||
error: str
|
||||
"""错误描述信息"""
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class IndividualBatchBuildResult:
|
||||
"""一批独立构建任务的整体结果汇总。"""
|
||||
results: tuple[BuildResult, ...]
|
||||
"""成功完成的所有构建结果"""
|
||||
failures: tuple[IndividualBuildFailure, ...]
|
||||
"""所有失败的构建任务记录"""
|
||||
worker_count: int
|
||||
"""本次批量构建使用的并行工作进程数"""
|
||||
|
||||
|
||||
def individual_batch_worker_count(task_count: int, max_workers: int | None = None) -> int:
|
||||
"""根据任务数量计算合适的并行工作进程数。
|
||||
|
||||
综合考虑用户指定的最大进程数、CPU 核心数和内置上限,
|
||||
返回一个合理的并行度。
|
||||
|
||||
Args:
|
||||
task_count: 待执行的任务总数
|
||||
max_workers: 用户指定的最大并行工作进程数,为 None 时自动检测
|
||||
|
||||
Returns:
|
||||
应使用的并行工作进程数,任务数 <= 0 时返回 0
|
||||
"""
|
||||
if task_count <= 0:
|
||||
return 0
|
||||
if max_workers is not None:
|
||||
# 以用户指定值为上限,最少 1 个进程
|
||||
return min(task_count, max(1, int(max_workers)))
|
||||
# 自动检测:取任务数、CPU 核心数、内置上限三者中的最小值
|
||||
detected_cpu_count = os.cpu_count() or 1
|
||||
return min(task_count, max(1, detected_cpu_count), INDIVIDUAL_BATCH_MAX_WORKERS)
|
||||
|
||||
|
||||
def _build_individual_task(task: IndividualBuildTask) -> BuildResult:
|
||||
"""执行单个构建任务,调用核心构建函数。
|
||||
|
||||
Args:
|
||||
task: 单个独立构建任务
|
||||
|
||||
Returns:
|
||||
BuildResult: 构建结果
|
||||
"""
|
||||
return build_packed_3mf([task.job], task.options)
|
||||
|
||||
|
||||
@@ -48,12 +88,25 @@ def _run_individual_batch_serial(
|
||||
tasks: Sequence[IndividualBuildTask],
|
||||
worker_count: int,
|
||||
) -> IndividualBatchBuildResult:
|
||||
"""串行方式执行一批独立构建任务。
|
||||
|
||||
逐个执行任务,捕获每个任务的异常并记录为失败。
|
||||
|
||||
Args:
|
||||
tasks: 要执行的任务序列
|
||||
worker_count: 工作进程数(此处仅用于结果记录)
|
||||
|
||||
Returns:
|
||||
IndividualBatchBuildResult: 包含成功和失败记录的批量结果
|
||||
"""
|
||||
results: list[BuildResult] = []
|
||||
failures: list[IndividualBuildFailure] = []
|
||||
for index, task in enumerate(tasks):
|
||||
try:
|
||||
# 逐个同步执行构建
|
||||
results.append(_build_individual_task(task))
|
||||
except Exception as exc:
|
||||
# 捕获任意异常,记录为失败项
|
||||
failures.append(IndividualBuildFailure(index, task.job, str(exc)))
|
||||
return IndividualBatchBuildResult(tuple(results), tuple(failures), worker_count)
|
||||
|
||||
@@ -62,29 +115,50 @@ def run_individual_batch_builds(
|
||||
tasks: Sequence[IndividualBuildTask],
|
||||
max_workers: int | None = None,
|
||||
) -> IndividualBatchBuildResult:
|
||||
"""并行执行一批独立构建任务。
|
||||
|
||||
当计算出的工作进程数 > 1 时,使用 ProcessPoolExecutor 并行处理;
|
||||
否则回退到串行执行。并行模式下按原始索引位置收集结果。
|
||||
|
||||
Args:
|
||||
tasks: 要执行的任务序列
|
||||
max_workers: 最大并行工作进程数,为 None 时自动检测
|
||||
|
||||
Returns:
|
||||
IndividualBatchBuildResult: 包含成功和失败记录的批量结果
|
||||
"""
|
||||
task_list = list(tasks)
|
||||
worker_count = individual_batch_worker_count(len(task_list), max_workers)
|
||||
# 单进程或无任务时,使用串行路径
|
||||
if worker_count <= 1:
|
||||
return _run_individual_batch_serial(task_list, worker_count)
|
||||
|
||||
# 预分配结果槽位,保证按原始顺序输出
|
||||
ordered_results: list[BuildResult | None] = [None] * len(task_list)
|
||||
failures: list[IndividualBuildFailure] = []
|
||||
# 使用进程池并行执行
|
||||
with ProcessPoolExecutor(max_workers=worker_count) as executor:
|
||||
# 提交所有任务并记录 future 到索引的映射
|
||||
future_to_index = {
|
||||
executor.submit(_build_individual_task, task): index
|
||||
for index, task in enumerate(task_list)
|
||||
}
|
||||
# 按完成顺序收集结果
|
||||
for future in as_completed(future_to_index):
|
||||
index = future_to_index[future]
|
||||
task = task_list[index]
|
||||
try:
|
||||
# 获取结果,放入对应位置
|
||||
ordered_results[index] = future.result()
|
||||
except Exception as exc:
|
||||
# 捕获任务执行异常,记录为失败
|
||||
failures.append(IndividualBuildFailure(index, task.job, str(exc)))
|
||||
|
||||
# 过滤掉未成功的位置(None),保留有效结果
|
||||
results = tuple(result for result in ordered_results if result is not None)
|
||||
return IndividualBatchBuildResult(
|
||||
tuple(results),
|
||||
# 按原始索引排序失败记录,便于阅读
|
||||
tuple(sorted(failures, key=lambda item: item.index)),
|
||||
worker_count,
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user