---
title: "切片执行"
description: "说明 assignment 枚举、原生 chunk 并行、确定性归并以及总工作量和驻留内存。"
eyebrow: "切片与执行"
---

## 单个 slice 的执行过程 {#one-slice}

执行器先验证输入 shape 和 sliced legs。对一个 assignment，它在原输入张量上选择对应轴值，构造移除 sliced legs 的单片网络，再复用原 SSA path 执行完整收缩。最后一条切片腿在 mixed-radix 编号中变化最快。

```diagram
slicing-execution
两条切片腿的 mixed-radix 算例：最后一条腿变化最快。连续 slice index 组成 chunk；chunk 内顺序累加、chunk 间并行、最终按 chunk index 合并。
```

```rust
use arctn::contract_network_sliced;

let output = contract_network_sliced(
    &net, &tensors, &ssa_path, &sliced_legs
)?;
```

## 原生执行的 chunk 与归并顺序 {#native-chunks}

单机原生执行把连续 slice index 范围分成若干 chunks。每个 chunk 内按 slice 编号顺序累加；Rayon 可以并行处理不同 chunks；全部完成后，再按 chunk index 串行合并 partial sums。chunk 划分只依赖切片数和输出元素数，不依赖当前线程数。

| 性质 | 实现语义 |
| --- | --- |
| chunk 数上限 | 最多 256，并受 partial-output 元素预算进一步限制 |
| 线程变化 | 改变 chunks 的完成时机，不改变 chunk 边界和最终合并顺序 |
| 空 sliced legs | 直接进入普通 contract\_network |
| 并发驻留 | 每个 in-flight slice 拥有自己的输入副本和中间结果 |

> **确定性范围**
>
> 线程数独立的归并顺序用于稳定单机浮点结果；它不意味着 MPI Allreduce 在不同 rank 数下也逐位相同。

## 总工作量与内存 {#cost-and-memory}

若切片数为 `N`, 总 FLOPs 是每片 FLOPs 乘 `N`。在对数报告中，`log10_flops_total = per_slice.log10_flops + log2(N) × log10(2)`。切片可能显著降低单片最大结果，同时因重复计算让总 FLOPs 上升。

| 随切片增加通常下降 | 随切片增加通常上升 |
| --- | --- |
| 单片最大中间结果 | 完整执行的 slice 数 |
| 单个子任务的路径模型内存 | 总 FLOPs 和输入读取 |
| 单片失败时的局部资源需求 | 任务调度、索引和结果累加开销 |

> [!WARNING]
> **驻留内存不是 target\_size**
>
> `target_size` 只限制单片的二元收缩结果，单张量网络则检查最终输出。原始输入、一元预处理、转置临时量、后端 workspace、partial sums 和同时执行的其他 slices 都会增加实际 RSS。需要总内存上限时，应同时控制并行度并实测进程内存。

## 三条执行路线 {#execution-routes}

| 路线 | assignment 调度 | 单片收缩 | 结果累加 |
| --- | --- | --- | --- |
| Rust / Python native | Rust 按固定 chunks，用 Rayon 并行 | ArcTN Rust CPU executor | chunk 内顺序、chunk 间固定顺序 |
| Python 显式外部 backend | Python 当前按固定顺序串行枚举 | 复用一个 opt\_einsum contract\_expression | 在所选数组 backend 上相加 |
| tnmpi 主模式 | 各 rank 得到不同连续 slice 区间 | 每个 rank 的 f64 原生执行 | MPI Allreduce |

三条路线共享同一个数学分解，但调度、同步、浮点归并顺序和计时边界不同。跨路线 benchmark 必须明确记录使用的是哪一条执行栈。
