与基于线程的并发模型相比,使用基于进程的并发模型的主要优点是什么?在什么情况下后者是合适的?
4 回答
容错性和可扩展性是使用进程与线程的主要优势。
依赖于共享内存或其他仅在使用线程时可用的技术的系统在您想在多台机器上运行系统时将毫无用处。迟早您将需要在不同进程之间进行通信。
例如,当使用进程时,您被迫通过消息处理通信,这就是 Erlang 处理通信的方式。数据不共享,因此不存在数据损坏的风险。
进程的另一个优点是它们可能会崩溃,并且您可以在知道可以重新启动它们(即使跨网络主机)时感到相对安全。但是,如果一个线程崩溃,它可能会导致整个进程崩溃,这可能会导致整个应用程序崩溃。举例说明:如果一个 Erlang 进程崩溃,你只会丢失那个电话,或者那个 webrequest 等等,而不是整个应用程序。
综上所述,操作系统进程也有许多缺点,使它们更难使用,例如需要永远生成一个新进程的事实。然而,Erlang 有自己的进程概念,非常轻量级。
话虽如此,这个讨论确实是一个研究课题。如果您想了解更多细节,可以阅读 Joe Armstrong 关于容错系统的论文] 1,它解释了很多关于 Erlang 和驱动它的哲学。
使用基于流程的模型的缺点是速度较慢。您将不得不在程序的并发部分之间复制数据。
使用基于线程的模型的缺点是您可能会弄错。这听起来可能很刻薄,但这是真的——给我看基于线程的代码,我会告诉你一个错误。我在已经“正确”运行了 10 年的线程代码中发现了错误。
使用基于流程的模型的优点很多。这种分离迫使您根据协议和正式的通信模式进行思考,这意味着您更有可能做到正确。相互通信的进程更容易跨多台机器横向扩展。多个并发进程允许一个进程崩溃,而不必使其他进程崩溃。
使用基于线程的模型的优点是速度快。
我更喜欢这两者中的哪一个可能很明显,但如果不是:流程,一周中的每一天和周日两次。线程太难了:我从来没有遇到过能写出正确多线程代码的人;那些声称能够通常对空间还不够了解的人。
在这种情况下,进程彼此更加独立,而线程共享一些资源,例如内存。但在一般情况下,线程比进程更轻量级。
Erlang Processes 与 OS Processes 不同。Erlang 进程非常轻量级,Erlang 可以在同一个 OS 线程中拥有多个 Erlang 进程。请参阅技术上为什么 Erlang 中的进程比操作系统线程更高效?
首先,进程与线程的主要区别在于它们的内存处理方式:
Process = n*Thread + memory region (n>=1)
进程有自己的独立内存。进程可以有多个线程。
进程在操作系统级别上相互隔离。线程与进程中的对等方共享它们的内存。(这通常是不可取的。有一些库和方法可以解决这个问题,但这通常是操作系统线程之上的人工层。)
记忆是最重要的辨别因素,因为它具有某些含义:
- 进程之间的数据交换比线程之间的要慢。打破进程隔离总是需要一些内核调用和内存重新映射的参与。
- 线程比进程更轻量级。操作系统必须为每个进程分配资源并进行内存管理。
- 使用进程可以为您提供内存隔离和同步。访问线程之间共享内存的常见问题与您无关。由于您必须特别努力在进程之间共享数据,因此您很可能会自动与之同步。
使用流程可以为您提供良好(或最终)的封装。由于进程间通信需要特别的努力,您将被迫定义一个干净的接口。将应用程序的某些部分从主可执行文件中分离出来是个好主意。也许您可以像这样拆分依赖项。例如Process_RobotAi <-> Process_RobotControl
,与控制组件相比,人工智能将具有截然不同的依赖关系。界面可能很简单:Process_RobotAI --DriveXY--> Process_RobotControl
. 也许你改变了机器人平台。您只需RobotControl
使用该简单接口实现一个新的可执行文件。您不必触摸甚至重新编译 AI 组件中的任何内容。
出于同样的原因,它也会在大多数情况下加快编译速度。
编辑:为了完整起见,我将无耻地添加其他人提醒我的内容:崩溃的过程不会(必然)使您的整个应用程序崩溃。
一般来说:
- 想要创建高度并发或同步的东西,例如具有 n>>1 个实例并行运行并共享数据的算法,请使用线程。
- 拥有一个包含多个组件的系统,这些组件不需要共享数据或算法,也不需要过于频繁地交换数据,使用流程。如果您使用 RPC 库进行进程间通信,则无需额外费用即可获得网络可分发的解决方案。
1 和 2 是极端且不费吹灰之力的场景,两者之间的一切都必须单独决定。
有关大量使用 IPC/RPC 的系统的好(或很棒)示例,请查看ros。