本节包含编写并行代码的重要哲学,以及关于 parallel 内部实现的一些细节。
这种哲学被 parallel 所采纳,其起源于 Go,Go 是目前编写并行代码最受推崇的平台之一。Go 程序员必须努力实现这一理想:PHP 和 parallel 为程序员完成了所有繁重的工作,并且默认情况下就是如此。
在其他语言中发现的传统线程模型中,线程通常通过它们在同一个地址空间中运行这一事实来相互通信。程序员必须部署互斥量、条件变量和其他低级线程或同步原语,以确保状态和一致性的正确通信。
当传统模型被颠倒时,这意味着线程仅通过通信共享内存(例如,一个变量通过 Channel 传递)。
当 parallel 通过任何方式将变量从一个线程传递到另一个线程时 - 任务参数、通过 Future 返回以及 Channel - 都是按值传递的。除无缓冲通道外,该变量也会被缓冲,因此它在被传递到的任何线程中使用之前不会更改(或被销毁)。通过通道的无缓冲读取是唯一一种线程直接读取另一个线程分配的内存的情况,它可以安全地执行,因为拥有内存的线程会等待读取完成才能继续操作,而没有拥有内存的线程则按值读取。当两个线程继续执行时,它们不再共享内存。
这使得编写和推理并行代码比传统的线程模型更容易。这意味着程序员不需要考虑线程可能并发地操作数据,因为这是不可能的。
这也使 PHP 成为实现基于 CSP(通过通道传递消息)的并行并发 API 的完美平台,因为 PHP 本身是无共享的 - PHP 线程默认情况下在其自己的虚拟地址空间中运行,因此只能通过通信共享内存。
在第一次接触 CSP 模型时,精通传统线程模型的程序员可能会发现自己正在寻找并发数据结构,因为这是他们习惯的:他们传递共享对象进行操作。
对于 CSP 模型而言,不需要数据结构被多个任务共享,事实上,如果它们不被共享,则会更简单。数据应由单个任务拥有,对该数据结构的更改(或操作)应通过通道进行通信,并由数据的拥有者执行,更改(或操作)的成功、失败或结果(状态)应传回。
再一次,PHP 的无共享性质和 parallel 的按值复制性质帮助程序员实现了这一目标,没有任何数据会意外地共享,只有通过通信才能共享。