程序执行与运行机制
从输入求值、名称绑定和调用解释程序结果,再建立等待、调度、资源与取消的模型。
从输入走到结果
程序是一组可由执行系统解释的规则。规则写在源码中,运行时拿到实际输入和当前状态,再决定下一步。假设一个订单处理过程读取数量 3 和单价 20,计算金额 60,随后写入订单。计算产生了一个值;写入改变了外部状态。这两个结果需要分别观察:函数返回 60,并不能证明订单已经保存。
理解一次执行至少要知道当前规则、名称对应的值、继续位置和已取得的资源。下面用抽象步骤说明,不假定机器逐条按此形式执行,也不承诺某种语言的内存布局。
输入数量与单价
→ 在当前环境中取得两个值
→ 按乘法规则求值
→ 把结果绑定到金额名称
→ 调用保存操作
→ 依据保存结果继续或失败求值是根据规则得到表达式结果;副作用是改变执行以外可见的状态,例如写文件、发送消息或更新共享对象。一个表达式是否纯粹取决于其行为:相同输入得到相同结果、执行时不改变外部状态,才符合这里使用的纯函数模型。时钟、随机数和可变全局状态也都是输入来源,不能因参数列表没有出现它们就忽略。
名称、作用域和存活期
名称用于引用值或存储位置。环境保存名称和所指对象之间的绑定;作用域决定代码在何处能解析某个名称。调用者和被调用者使用同一个拼写,并不意味着访问同一个绑定。局部变量可以遮蔽外部名称,模块也可以建立独立的名称空间。
作用域回答在哪里能引用,存活期回答对象在什么时候仍存在。返回的函数可能保留对创建时环境的引用,使有关对象在外层调用结束后继续可用;文件句柄也可能仍存在,却已经被关闭。语言如何捕获绑定、何时回收内存,以及资源关闭是否自动发生,需要在具体语言中确认。
因此排查“值变了”要追到同一对象的写入者;排查“找不到名称”要追名称解析规则;排查泄漏要查对象或资源仍被谁持有。三种问题的检查入口不同。
调用怎样继续
调用把输入交给另一个过程,并保留调用完成后应当继续的位置。同步调用中,调用者通常等待被调用者返回或抛出失败。嵌套调用形成待返回的链;栈是常见实现和解释模型,生成器、协程、尾调用或优化可能采用其他保存方式。
执行上下文是描述一次执行所需状态的模型。它可以包含当前代码、局部环境和继续信息,不能直接等同于一个操作系统线程。ECMAScript 规范尤其明确其执行上下文属于规范装置,具体实现无需提供一一对应的物理对象。这个限定说明了怎样使用模型,又保留了实现优化的空间。ECMAScript,执行上下文
返回值和异常提供不同的控制出口。可预期的拒绝可以显式作为结果交给调用者;无法满足内部假设的失败可以中断当前路径。资源清理要覆盖两个出口。把所有错误吞掉并返回空值,会让调用者无法分辨“确实没有记录”和“读取失败”。
等待、并发与调度
保存订单可能等待网络或磁盘。阻塞模型让当前执行单元等待;异步模型保存继续信息,允许当前执行单元处理其他工作,等条件满足后再恢复。异步把等待和继续分开,并没有保证业务操作已经完成。
并发表示多个活动的时间范围重叠;并行表示多个活动在同一时刻实际执行。单线程事件循环可以并发处理多个等待中的请求,多线程或多进程可以在条件允许时并行计算。语言调用规则、宿主调度和操作系统调度共同影响结果,不能把所有运行系统都解释成一个事件队列。
假设下载和金额计算同时开始。下载交给外部 I/O,计算在当前执行单元进行;计算耗时很长时,即使下载已经就绪,处理结果的回调也可能暂时得不到执行机会。响应慢需要区分外部等待、计算占用、排队和资源不足。Java 的官方并发教材也分别讨论线程、同步和执行器;它是一个实现家族的说明,页面以 JDK 8 为基线,不承担当前 Java API 推荐。Oracle,并发教材
取消、期限和资源
取消请求表达调用方希望停止继续工作。执行方需要在可中断的位置观察请求,并决定停止哪些操作、怎样清理资源。调用方停止等待,只改变调用方的状态;服务端已经写入的订单仍然存在。超时同样说明在期限内没有得到结果,外部效果可能成功、失败或尚在进行。
设计取消时,明确请求如何传递、什么位置检查、外部 API 是否接受中断、已经完成的效果如何处理。资源的取得与释放应有对应关系:打开连接后关闭、订阅后取消、创建定时器后移除。长期持有资源要有明确所有者。
用运行事实校验模型
分析执行问题时记录输入、执行入口、状态变化和可观察结果。只读源码能确认规则和调用路径;测试能确认所测输入;实际环境的调度、I/O 和资源上限需要对应运行证据。本文示意过程用于解释关系,没有声称已在所有运行环境执行。
本页吸收归档 TypeScript 语言、工程分稿和生成性知识地图中的执行关系,并补充跨运行模型的边界。JavaScript 的词法环境、Promise 和宿主队列在语言实践中按具体规则展开。
最后更新于