Files
endorphin-tabularium-docs/content/docs/language-design/12-questions.md
T
codex-bot ef1ba88161
Verify and deploy Tabularium / verify-and-deploy (push) Waiting to run
Add language design question collection with discussion decisions and provenance
2026-10-28 14:02:12 +08:00

8.3 KiB
Raw Blame History

12 · 并发与异步

0/21 项已确认。当前推进 12-01;本分类尚未完成选择。

本页整理原讨论的问题、验收要求和候选方案。勾选代表讨论中已确认的规则,不代表编译器或运行时已经实现。

12-01 可变状态的共享规则

  • 待讨论

确定普通可变值默认能否跨执行单位共享,以及允许共享的条件、违规后果。

12-02 数据跨边界传递

  • 待讨论

确定参数、闭包捕获和消息采用复制、共享还是转移;明确嵌套引用及发送后继续访问的规则。依赖:对象与类型模型。

12-03 支持哪些执行单位

  • 待讨论

确定是否提供线程、任务、协程或其他单位,明确各自能力及相互关系;不支持的单位也明确记录。

12-04 并行能力与边界

  • 待讨论

确定哪些执行单位允许同时执行,哪些必须串行,以及程序能否依赖特定并行度。

12-05 创建、启动与生命周期

  • 待讨论

确定工作何时启动、由谁管理、能否脱离创建者,以及作用域退出时如何处理未结束工作。

12-06 等待结果与失败传播

  • 待讨论

确定等待一次或多次的行为、结果保存方式、未观察错误,以及多个子任务失败时的处理。依赖:异常与错误处理。

12-07 异步暂停与调用规则

  • 待讨论

确定暂停是否显式、哪些上下文允许等待、可等待值的协议,以及普通调用与异步调用如何组合。依赖:函数与定制协议。

12-08 阻塞操作与异步的衔接

  • 待讨论

确定同步 I/O、阻塞调用进入任务后的行为,以及是否提供转交线程等机制;明确误用后果。

12-09 取消与清理

  • 待讨论

确定谁能请求取消、何时生效、能否屏蔽、如何观察取消,以及清理代码能否继续等待。依赖:资源管理、异常与错误处理。

12-10 超时与竞争等待

  • 待讨论

确定超时是否取消工作、多路等待如何选胜者、同时完成如何处理,以及落选工作由谁回收。

12-11 调度与进展保证

  • 待讨论

确定切换时机、协作式或抢占式约束、饥饿与公平性保证,以及执行单位能否迁移线程。

12-12 显式同步工具

  • 待讨论

确定支持哪些锁、条件变量或信号量;明确重入、持锁暂停、取消等待和死锁的处理。

12-13 消息与通道

  • 待讨论

确定是否支持消息机制;若支持,明确顺序、容量、背压、关闭、发送失败与接收结束的行为。

12-14 原子操作

  • 待讨论

确定是否提供原子值及操作;若支持,明确操作范围、内存顺序和不支持的值类型。依赖:类型系统、数值与基础类型。

12-15 内存可见性与数据竞争

  • 待讨论

明确同步建立什么可见性保证,以及未同步冲突访问是被拒绝、报错,还是具有某种规定的后果。

12-16 运行时自身的并发保护

  • 待讨论

明确 GIL、对象级锁、隔离堆等候选机制必须保障什么,以及哪些实现选择可以保留自由;区分运行时安全与用户操作的原子性。依赖:运行时实现。

12-17 复合操作与重入

  • 待讨论

明确单次安全操作能否组合成事务;规定回调、用户代码重入及跨多个值维护不变量时的保证。依赖:对象与定制协议。

12-18 资源与对象生命周期的交互

  • 待讨论

明确任务退出、共享对象存活、资源关闭、终结处理与并发访问发生冲突时的规则。依赖:内存管理、资源管理。

12-19 外部代码与外来线程

  • 待讨论

确定是否支持外部阻塞调用、外来线程进入语言和跨边界回调;明确同步责任及违规后果。依赖:外部接口、运行时实现。

12-20 执行上下文与局部状态

  • 待讨论

确定线程局部、任务局部或等价机制是否存在,以及创建、迁移、取消时如何继承和释放。

12-21 跨分类一致性与最终验收

  • 待讨论

用代表性场景检查上述规则能否共同成立,解决跨分类冲突,并形成最终规则摘要。

当前问题的方案与语言对照

以下沿用原讨论材料;建议和参考语言的做法均不自动成为本语言规则。

当前仍是 12-01:普通可变数据能否跨执行单位直接共享,以及谁负责保证安全。 这里允许不同边界采用不同规则,例如同一线程内的任务与可能并行的工作之间,可以有不同限制。

现有语言提供了四种有用的参考:

语言 规则与具体行为 好处、代价及启发
Python 同一解释器中的线程可以持有同一个列表、字典等对象。程序员可以用同一把锁保护“检查库存+扣减”。GIL 是 CPython 的实现机制;CPython 也有自由线程构建,内置容器的内部保护不能替代业务同步。官方文档 共享方便,但同步责任主要由程序员承担。启发:必须分别说明“对象内部安全”和“整段业务操作正确”。
JS/TS 同一 JS agent 内的异步工作可以访问同一个普通对象;跨 await 的操作仍可能交错。浏览器 Worker 之间通常通过消息复制或转移数据,不能直接共享普通对象;共享内存可显式使用 SharedArrayBuffer,配合原子操作。Worker 属于宿主提供的机制。ECMAScript、HTML 标准 普通对象跨 Worker 的隔离减少直接共享风险,但有传递成本;显式共享内存增加复杂性。启发:可以采用“局部共享、跨并行边界默认隔离”。
Go goroutine 可以直接共享变量,但冲突访问必须同步。例如两个 goroutine 访问同一库存,可以用 sync.Mutex 保护;也可以让一个 goroutine 管理库存,其他工作通过 channel 请求。channel 不会自动剥夺发送者对所发送指针的访问权。内存模型、Effective Go 共享内存和消息协作都方便;“发送后不再访问”通常需要程序员遵守。启发:提供消息工具与强制隔离是两个不同决定。
Rust 安全 Rust 通过所有权、借用和跨线程约束限制危险共享。共享修改库存可以使用 Arc<Mutex<库存>>;访问锁内数据需要取得锁守卫,普通 Rc 则不能直接跨线程传递。官方教程 能提前拒绝部分危险访问,但规则和类型更复杂,也仍可能死锁或出现业务竞态。启发:可以把“满足条件才能共享”做成可检查的规则。

其中,TS 没有独立的并发运行时,实际行为依赖生成的 JS 和宿主环境。readonly 等静态限制也不会自动提供运行时冻结或同步保护。TS 对象类型文档

回到我们的三个候选方向:

  • A.默认允许共享,使用者负责同步。 接近 Python 线程、Go 共享变量的使用方式。表达直接,但容易遗漏同步。
  • B.跨并行边界默认隔离,通过消息协作。 可以参考浏览器 Worker 的普通对象边界。管理责任清楚,但必须明确复制、转移和响应规则。
  • C.只有满足检查规则才能共享或转移。 可以参考 Rust。能更早发现危险用法,但依赖更完整的别名、所有权或运行期检查设计。

我的暂定建议是优先考虑 B:先让普通可变数据跨并行边界的归属清楚,再讨论是否提供显式共享机制。它也有成本:频繁交换大型数据时,需要认真设计传递方式。如果我们的目标更偏向细粒度共享和底层控制,C 值得优先考虑。这个建议尚未成为决定。

你更倾向 A 的直接共享、B 的默认隔离,还是 C 的受检查共享?如果你的偏好是“同一线程内共享、跨并行边界隔离”,也可以直接这样确定方向。

讨论来源

《语言设计 12:并发与异步》,整理日期 2026-10-28。章节编号沿用原清单。