``Dropping CustomSmartPointer with data `some data`!`` 出现在 `CustomSmartPointer created.` 和 `CustomSmartPointer dropped before the end of main.` 之间,表明了 `drop` 方法被调用了并在此丢弃了`c`。
文本 ``Dropping CustomSmartPointer with data `some data`!`` 会出现在 `CustomSmartPointer created.` 和 `CustomSmartPointer dropped before the end of main.` 之间,这表明 `drop` 方法的代码在那个时刻被调用,以丢弃`c`。
在大多数当前的操作系统中,一个运行中的程序代码会在一个**进程**(*process*)中执行,而操作系统会同时管理多个进程。在一个程序内部,也可以存在彼此独立、同时运行的多个部分。运行这些独立部分的功能被称为**线程**(*threads*)。例如,一个 web 服务器可以拥有多个线程,以便同时响应多个请求。
一个日益流行的确保安全并发的方式是**消息传递**(_message passing_),这里线程或 actor 通过发送包含数据的消息来相互沟通。这个思想来源于 [Go 编程语言文档](https://golang.org/doc/effective_go.html#concurrency) 中的口号:“不要通过共享内存来通讯;而要通过通讯来共享内存。”(“Do not communicate by sharing memory; instead, share memory by communicating.”)
@ -25,7 +24,7 @@
这里使用 `mpsc::channel` 函数创建一个新的信道;`mpsc` 是 **多生产者,单消费者**(_multiple producer, single consumer_)的缩写。简而言之,Rust 标准库实现信道的方式意味着一个信道可以有多个产生值的 **发送端**(_sending_),但只能有一个消费这些值的**接收端**(_receiving_)。想象一下多条小河小溪最终汇聚成大河:所有通过这些小河发出的东西最后都会来到下游的大河。目前我们以单个生产者开始,但是当示例可以工作后会增加多个生产者。
下载文件则有所不同。它不占用大量的 CPU 时间。相反 CPU 需要等待来自于网络的数据。虽然可以在部分数据就绪时就开始读取,但等待剩余数据可能还需要一段时间。即便数据全部就绪了,视频文件也可能非常大,因此加载所有数据也会花费一些时间。虽然这可能只需要一两秒,不过这对于一个现代处理器来说已经是非常长的时间了,因为它每秒可以执行数十亿次操作。因此,如果能让 CPU 在等待网络调用完成的同时去处理别的工作就再好不过了。所以同上操作系统会隐式地中断你的程序以便其它工作可以在网络操作进行的同时继续进行。
来看一个例子。假设你正在导出一个家庭聚会的视频,这个操作可能要花上几分钟甚至几小时。视频导出会尽可能多地占用 CPU 和 GPU 资源。如果你只有一个 CPU 核,而操作系统又不会在导出完成前暂停这个任务,也就是说它会以*同步*方式执行导出,那么在这个任务运行期间你就什么别的都做不了。这会是相当糟糕的体验。幸运的是,你的操作系统可以,而且确实会,足够频繁地打断导出任务,让你同时完成其他工作。
再假设你正在下载别人分享给你的视频。这个操作也可能耗时很长,但不会占用太多 CPU 时间。此时 CPU 主要是在等待网络数据到达。虽然数据一开始到达时你就可以开始读取,但全部数据到齐仍然可能需要一段时间。即便数据已经全部到达,如果视频文件很大,完整载入它也至少可能需要一两秒。听起来不算长,但对于每秒能执行数十亿次操作的现代处理器来说,这已经是很长的时间了。和前面的例子一样,操作系统也会在等待网络调用完成时悄悄打断程序,让 CPU 去处理其他工作。
视频导出属于 **CPU 密集型**(*CPU-bound*)或 **计算密集型**(*compute-bound*)操作:它受限于 CPU 或 GPU 处理数据的速度,以及操作能分配到多少计算能力。视频下载则属于 *I/O-bound* 操作,因为它受限于计算机的 *输入输出*(*input and output*)速度;它的速度最多只能和网络传输数据的速度一样快。
同样的基础动态也作用于软件与硬件。在一个单核的机器上,CPU 一次只能执行一个操作,不过它仍然可以并发工作。借助像线程、进程和异步(async)等工具,计算机可以暂停一个活动,并在最终切换回第一个活动之前切换到其它活动。在一个有多个 CPU 核心的机器上,它也可以并行工作。一个核心可以做一件工作的同时另一个核心可以做一些完全不相关的工作,而且这些工作实际上是同时发生的。