# 3.4并发：时间是关键

> 译者： [https://sicp.comp.nus.edu.sg/chapters/63](https://sicp.comp.nus.edu.sg/chapters/63)



我们已经看到了具有局部状态的计算对象作为建模工具的强大功能。 然而，正如 [3.1.3](51) 所警告的那样，这种力量带来了代价：参照透明性的丧失，引发了关于相同性和变更的疑问，以及放弃的必要性 评价的替代模型支持更复杂的环境模型。

潜伏在状态，相同性和变化的复杂性中的核心问题是，通过引入分配，我们被迫将_时间_纳入我们的计算模型。 在引入赋值之前，我们的所有程序都是永恒的，因为任何具有值的表达式始终具有相同的值。 相比之下，请回想一下在 [3.1.1](49) 的开头部分介绍的从银行帐户取款建模并返回结果余额的示例：

```js
withdraw(25); // output: 75
```

```js
withdraw(25); // output: 50
```

在此，对相同表达式的连续求值得出不同的值。 此行为是由于以下事实引起的：赋值语句（在这种情况下，为变量`balance`的赋值）的执行在值更改时描绘了_时刻_。 评估表达式的结果不仅取决于表达式本身，还取决于评估是在这些时刻之前还是之后进行的。 根据具有局部状态的计算对象来构建模型迫使我们面对时间，这是编程中必不可少的概念。

我们可以进一步构建计算模型以匹配我们对物理世界的认识。 世界上的物体不会一次改变一个。 相反，我们认为它们同时充当_和_。 因此，通常将系统建模为同时执行的计算过程的集合。 正如我们可以通过根据具有单独局部状态的对象来组织模型来使程序模块化一样，通常将计算模型划分为可以分别并发发展的部分是合适的。 即使要在顺序计算机上执行程序，编写程序也要同时执行的做法迫使程序员避免不必要的时序约束，从而使程序更具模块化。

除了使程序更具模块化之外，并发计算还可以提供比顺序计算更快的速度。 顺序计算机一次只能执行一个操作，因此执行任务所花费的时间与执行的操作总数成正比。 [[1]](63#footnote-1)

但是，如果有可能将问题分解为相对独立且仅需要很少通信的组件，则可以将组件分配给单独的计算处理器，从而产生与可用处理器数量成比例的速度优势。

不幸的是，在并发的情况下，分配带来的复杂性变得更加成问题。 并发执行的事实，可能是因为世界是并行运行的，或者因为我们的计算机同时运行，这使得我们对时间的理解更加复杂。

* * *

[[1]](63#footnote-link-1) Most real processors actually execute a few operations at a time, following a strategy called _pipelining_. Although this technique greatly improves the effective utilization of the hardware, it is used only to speed up the execution of a sequential instruction stream, while retaining the behavior of the sequential program.

