Skip to content

⚠️ 已废弃 (DEPRECATED)

本 RFC 已被 RFC-024:新并发模型 取代。

RFC-001 的三层并发架构(L1/L2/L3)、@block/@eager 注解、DAG 自动分析等设计已被移除。新设计使用 spawn {} 块作为唯一并行原语,无需注解。

本文档仅作历史参考保留。



title: "RFC-001:并作模型与错误处理系统"

RFC-001:并作模型与错误处理系统

设计来源

文档关系
async-whitepaper设计源头,理论基础
language-spec规范目标

摘要

提出 YaoXiang 的并作模型:以同步语法描述逻辑,运行时自动并发执行。核心机制:三层并发架构 + DAG 依赖分析 + Result 类型系统。

快速选择

场景写法说明
自动并行不写注解(默认)最大化并行
同步等待@eager等待依赖完成
完全顺序@block无并发,调试用
局部并发spawn@block 作用域内并发

动机

当前主流语言的并发模型存在明显缺陷:

语言并发模型问题
Rustasync/await + tokio异步传染、学习曲线陡峭
Gogoroutine无类型安全
PythonasyncioGIL 限制
JavaScriptPromise/async回调复杂

核心矛盾

  1. 透明性 vs 可控性:完全透明但不可控 vs 完全可控但不透明
  2. 并发 vs 可调试:并发程序难调试 vs 可调试程序难并发

提案

1. 并作模型:三层并发架构

说明:L1/L2/L3 是心智模型,帮助用户理解不同场景。实际实现只有一套机制:DAG 自动分析 + 注解控制。

层级心智模型语法执行方式并行度
L1禁止并发@block纯顺序执行❌ 无
L2@block 内并发spawn@block 作用域内可控并发⚠️ 部分
L3完全并发默认(无注解)自动分析 DAG✅ 完整

L1: @block 同步模式

yaoxiang
main: () -> Void @block = {
    data1 = fetch_sync("api1")
    data2 = fetch_sync("api2")
    process(data1, data2)    # 严格顺序,无并发
}

L2: @block 内可控并发

yaoxiang
# spawn 只能在 @block 函数内部使用
main: () -> Void @block = {
    spawn { data1 = fetch_data("api1") }
    spawn { data2 = fetch_data("api2") }
    # 等待所有 spawn 完成(标准库控制)
    process(data1, data2)
}

L3: 完全透明(默认)

yaoxiang
# 不需要任何注解,编译器自动分析 DAG
heavy_calc: (n: Int) -> Int = fibonacci(n)

auto_parallel: (n: Int) -> Int = {
    a = heavy_calc(1)    # 自动并行
    b = heavy_calc(2)    # 自动并行
    c = heavy_calc(3)    # 自动并行
    a + b + c            # 需要值时等待所有结果
}

2. 注解完整对比

维度默认(无注解)@eager@blockspawn
执行方式自动 DAG 分析同步等待依赖纯顺序@block 内并发
并行度✅ 完全⚠️ 按依赖顺序❌ 无⚠️ 部分
DAG 构建

选择指南

  • 最大并发 → 不写注解(默认)
  • 需要有序副作用 → @eager
  • 调试/新手/关键代码 → @block
  • @block 内需要并发 → spawn
yaoxiang
# 默认:最大化并行
calc_all: () -> Int = {
    a = heavy_calc(1)    # 自动并行
    b = heavy_calc(2)    # 自动并行
    a + b
}

# @eager:同步等待
calc_seq: () -> Int @eager = {
    a = heavy_calc(1)    # 同步执行
    b = heavy_calc(2)    # 同步执行
    a + b
}

# @block:纯顺序
calc_simple: () -> Int @block = {
    a = heavy_calc(1)    # 强制同步
    b = heavy_calc(2)    # 同步
    a + b
}

# spawn:@block 内并发
calc_mixed: () -> Int @block = {
    spawn { heavy_calc(1) }
    spawn { heavy_calc(2) }
    heavy_calc(3)        # 同步
}

3. DAG 依赖分析

3.1 核心原则:自底向上执行

用户代码(同步语法):
    a = fetch(url0)
    b = fetch(url1)
    print(a)

编译时分析(自底向上):
    print(a) 需要 a → 依赖 fetch(url0)
    fetch(url1) 没有人需要 → 孤岛 DAG

运行时调度(从叶子开始):
    fetch(url0) → print(a)    ← 依赖链,按序
    fetch(url1)                ← 孤岛,独立并行

关键洞察:不是"自顶向下"生成 Future,而是"自底向上"从结果反向分析依赖。

3.2 孤岛 DAG:独立并行

主流程:fetch(url0) → process → print
孤岛:  fetch(url1)  ← 没人要结果,独立并行

调度器:主流程按依赖链执行,孤岛用另一核心并行

3.3 资源类型与副作用

核心思想:资源操作通过类型标记,DAG 自动构建依赖。同一资源自动串行,不同资源自动并行。

资源类型边界——明确定义

资源类型是编译器内置标记的类型。以下类型被编译器识别为资源:

资源类型说明编译器行为
FilePath文件系统路径同路径操作自动串行
HttpUrlHTTP 端点同 URL 操作自动串行
DBUrl数据库连接同连接操作自动串行
Console标准输出所有 Console 操作自动串行

用户自定义资源类型需显式标记:

yaoxiang
Database: Resource              # 显式标记为资源类型
query: (Database, String) -> Result(Row, Error)
# 参数 Database 是 Resource,自动识别为资源操作

非 Resource 标记的类型不会被编译器追踪资源依赖。

使用规则

  • 通过变量传递资源句柄,DAG 自动管理顺序
  • 字面量直接使用同一资源是用户设计问题,非语言责任
yaoxiang
# ✅ 正确:变量传递,DAG 自动串行
filename: String = "data.txt"
File.write(filename, x)
File.write(filename, y)    # DAG 串行

# ⚠️ 用户责任:字面量
File.write("data.txt", x)
File.write("data.txt", y)  # 可能并行,用户自己负责

3.4 无限循环处理

1 个循环 → 直接同步执行,零调度开销
多个循环 → 调度器切片切换,真正并发

4. Result 类型与错误处理

yaoxiang
Result: (T: Type, E: Type) -> Type = { ok: (T) -> Self, err: (E) -> Self }

# ? 运算符透明传播
process: () -> Result(Data, Error) = {
    data = fetch_data()?
    processed = transform(data)?
    save(processed)?
}

5. DAG 节点设计

rust
enum NodeKind {
    Task,      // 任务节点
    Value,     // 值节点
    Control,   // 控制流节点
}

struct Node {
    id: NodeId,
    kind: NodeKind,
    inputs: Vec<ValueNodeId>,   // 输入依赖
    outputs: Vec<ValueNodeId>,  // 输出值
    span: Span,                 // 源码位置
}
边类型符号语义
DataEdge数据依赖(值流动)
ControlEdge控制依赖(顺序执行)
SpawnEdge并发入口(可并行起点)

6. 类型系统

Send → 可安全跨线程传输
Sync → 可安全跨线程共享
Arc(T) 实现 Send + Sync(线程安全引用计数)

权衡

优点

  1. 渐进式采用:三层模型适应不同技能水平
  2. 自然语法:同步代码获得并行性能
  3. 编译时安全:Send/Sync 约束消除数据竞争
  4. 可调试:错误图提供清晰的错误传播视图

缺点

  1. 学习曲线:需要理解 DAG 依赖概念
  2. 编译时间:全程序 DAG 分析可能较慢
  3. 工具链复杂度:需要全新的调试和可视化工具

替代方案

方案为什么不选择
仅支持显式 async/await无法实现透明并发
仅支持完全透明并发用户失去控制权
Go 式 goroutine无类型安全、无法编译时检查
仅 L1 模式放弃并作模型核心价值

实现策略

阶段划分

  1. 阶段 1 (v0.1):@block 同步模式、基础类型
  2. 阶段 2 (v0.2):FlowScheduler 调度器
  3. 阶段 3 (v0.3):spawn 块、显式并发
  4. 阶段 4 (v0.5):L3 完全透明、DAG 自动分析
  5. 阶段 5 (v0.6):错误图、图调试器
  6. 阶段 6 (v1.0):生产可用优化

依赖关系

  • RFC-001 无外部依赖(基础核心)
  • RFC-008(Runtime 并发模型)→ 设计完成
  • RFC-011(泛型系统)→ 设计完成

风险

  1. DAG 分析性能:全程序分析可能 O(n²),需要优化
  2. 工具链缺失:调试器需要从零开发
  3. 用户接受度:透明并发需要良好文档

设计决策记录

决策决定日期
三层并发架构L1/L2/L3 渐进式2025-01-05
@block 注解位置返回类型后2025-01-05
DAG 错误传播沿依赖边向上游传播2025-01-06
DAG 性能优化增量构建 + 缓存2025-01-06
运行时选择泛型 + 编译时注入2025-01-06
节点接口泛型 + 函数注入(无 trait)2025-01-06
错误图内存DAG 仅在单函数内构建2025-01-06
资源冲突检测DAG 数据流依赖,用户变量传递2025-01-06
资源类型系统Resource 标记 + DAG 自动依赖2026-01-06
L1/L2/L3 心智模型三层抽象,非实现机制2026-01-06
@auto 注解删除,与默认行为重复2026-05-11
L1 自动回退删除,行为不可预测2026-05-11

附录:术语表

术语定义
并作模型YaoXiang 的并发范式:同步语法,异步本质
DAG有向无环图,描述计算依赖关系
spawn@block 作用域内可控并发
@block同步注解,禁用并发优化
@eager急切求值,等待依赖完成
Resource资源类型标记,操作自动构建 DAG 依赖
错误图可视化的错误传播路径

参考文献