Administrator
发布于 2025-09-04 / 2 阅读
0
0

并发计算模型

并发计算模型是理解和构建并发系统(如多线程程序、分布式系统)的理论和抽象框架。

1. 线程与锁模型

这是最传统、最接近底层(操作系统)的模型,也是大多数程序员最先接触的模型。

  • 核心思想:并发的基本单位是线程。多个线程共享同一进程的内存空间(共享内存)。通过(如互斥锁Mutex、信号量Semaphore)等同步原语来协调线程对共享资源的访问,防止竞争条件。

  • 优点

    • 直观:映射到操作系统的实现方式。

    • 控制力强:细粒度的锁可以提供高性能。

  • 缺点

    • 极易出错:容易产生死锁、活锁、优先级反转、数据竞争等问题。

    • 难以测试和调试:并发问题常常难以复现。

    • 可伸缩性差:在高度并发时,锁会成为性能瓶颈。

  • 典型代表Pthreads(POSIX线程), Java synchronized 关键字C++ std::threadstd::mutex

2. actor模型

一种基于消息传递的更高层次的抽象,由Carl Hewitt在1973年提出,非常适合分布式系统。

  • 核心思想

    1. Actor是并发计算的基本单元。每个Actor是一个轻量级的实体。

    2. 封装状态:每个Actor有自己的私有状态,并且不与其他Actor共享内存。状态变更只能由自己进行。

    3. 异步消息传递:Actor之间只能通过发送异步消息进行通信。

    4. 邮箱:每个Actor有一个邮箱(消息队列),用于接收来自其他Actor的消息。

    5. 处理行为:Actor顺序地处理其邮箱中的消息。处理消息时,它可以:

      • 改变其内部状态。

      • 发送消息给其他Actor。

      • 创建新的Actor。

  • 优点

    • 强隔离性:不存在共享内存,从根本上避免了数据竞争和锁的问题。

    • 位置透明性:Actor可以在本地,也可以在远程机器上,通信机制在理想情况下是一致的。

    • 容错性好:容易实现“监督树”等错误恢复机制。

  • 缺点

    • 消息传递有性能开销(但避免了锁竞争)。

    • 业务逻辑可能变得“碎片化”,分布在多个Actor的消息处理中。

  • 典型代表Erlang(最著名的实现), Akka(Java/Scala框架), Orleans (.NET)。

3. 通信顺序进程模型

由Tony Hoare提出的理论模型(CSP, Communicating Sequential Processes),与Actor模型类似,也基于消息传递,但有一个关键区别。

  • 核心思想

    1. CSP的并发实体(进程)是匿名的,它们不直接持有对方的引用。

    2. 通信通过通道(Channel) 进行。进程必须通过共享的通道来发送和接收消息。

    3. 同步是核心:通信本身是同步的(** rendezvous, 会合**)。即,发送方和接收方必须同时准备好(在通道两端“会合”),消息才会被传递。否则,准备好的一方会被阻塞。

      • (注:许多现代实现也提供了带缓冲的异步通道作为选项)

  • 与Actor模型的区别

    特性

    Actor模型

    CSP模型

    通信对象

    直接向某个确定的Actor发送消息

    向一个通道(Channel) 发送或接收消息

    通信方式

    通常是异步

    核心是同步(会合),可选异步缓冲

    关注点

    强调实体(Actor)

    强调通道(Channel) 这个通信媒介

  • 优点:与Actor类似,避免了共享内存的陷阱。同步通信使数据流更加明确。

  • 典型代表Go 语言(Goroutine + Channel是其核心并发原语), Occam 语言。

4. 数据并行模型

专注于同时对集合中的不同元素执行相同的操作。

  • 核心思想:将大规模数据分成若干块,然后将这些块分配给多个处理单元(CPU核心、机器)并行处理。

  • 优点

    • 抽象层次高:程序员只需指定“做什么”(对哪些数据执行什么操作),而不必关心“怎么做”(线程、锁、任务分配)。

    • 非常高效:特别适合科学计算、图形处理、大数据分析等计算密集型任务。

  • 缺点:适用场景有限,主要针对可以高度并行化的、计算模式统一的任务。

  • 典型代表MapReduce(Hadoop), CUDA(NVIDIA GPU编程), OpenMP(C++/Fortran等语言的指令集), Apache Spark

5. 函数式并发

基于函数式编程的不可变性和无副作用特性。

  • 核心思想避免状态可变和共享。数据是不可变的(Immutable),函数是“纯函数”(输出只取决于输入,不产生副作用)。既然没有可变状态需要修改,自然也就不需要锁。

  • 实现方式:并发通常通过 Future/Promise 或惰性计算来实现。Future 代表一个尚未完成的计算结果,可以异步获取。

  • 优点安全。极大地降低了理解和推理并发程序的难度。

  • 缺点:需要改变编程思维模式;并非所有问题都适合用函数式表达;有时需要拷贝数据可能带来性能开销。

  • 典型代表Clojure(默认不可变数据结构), Scala(与Akka结合使用Future), Haskell(纯函数式语言)。


评论