三分钟掌握Actor和CSP模型

简介: 一直想比较Actor模型与golang的CSP模型,经过一段时间的实战记录了本文。

Actor vs CSP模型


  • • 传统多线程的的共享内存(ShareMemory)模型使用lock,condition等同步原语来强行规定进程的执行顺序。


  • • Actor模型,是基于消息传递的并发模型,   强调的是Actor这个工作实体,每个Actor自行决定消息传递的方向(要传递的ActorB),通过消息传递形成流水线。


09d79aa44d071ff513f8cd45d71834b2.png


本文现在要记录的是另一种基于消息传递的并发模型:CSP(communicating sequential process顺序通信过程)。


在CSP模型,worker之间不直接彼此联系,强调信道在消息传递中的作用,不谋求形成流水线。


消息的发送者和接受者通过该信道松耦合,发送者不知道自己消息被哪个接受者消费了,接受者也不知道是从哪个发送者发送的消息。


6cd2fc88d495e2e837de4b7e48802217.png


go的信道


go的信道[1]是golang协程同步和通信的原生方式。


同map,slice一样,channel通过make内置函数初始化并返回引用,引用可认为是常量指针[2]


两种信道:


  1. 无缓冲区信道:读写两端就绪后,才能通信(一方没就绪就阻塞)

这种方式可以用来在goroutine中进行同步,而不必显式锁或者条件变量。


2. 有缓冲区信道:就有可能不阻塞, 只有buffer满了,写入才会阻塞;只有buffer空了,读才会阻塞。


go的信道暂时先聊到这里。


我们来用以上背景做一道 有意思的面试题吧 。


两个线程轮流打印0到100?


我不会啥算法,思路比较弱智:#两线程#, #打印奇/偶数#, 我先复刻这两个标签。


通过go的无缓冲信道的同步阻塞的能力对齐每一次循环。


package main
import (
 "fmt"
 "strconv"
 "sync"
)
var wg sync.WaitGroup
var ch1 = make(chan struct{})
func main() {
 wg.Add(2)
 go func() {
  defer wg.Done()
  for i := 0; i <= 100; i++ {
   ch1 <- struct{}{}
   if i%2 == 0 { // 偶数
    fmt.Println("g0  " + strconv.Itoa(i))
   }
  }
 }()
 go func() {
  defer wg.Done()
  for i := 0; i <= 100; i++ {
   <-ch1
   if i%2 == 1 { // 奇数
    fmt.Println("g1 " + strconv.Itoa(i))
   }
  }
 }()
 wg.Wait()
}


题解:两个协程都执行0到100次循环,但是不管哪个线程跑的快,在每次循环输出时均会同步对齐, 每次循环时只输出一个奇/偶值, 这样也不用考虑两个协程的启动顺序。


fd3ad7800ce0c3f43483d225aa6ceea3.png


思考我的老牌劲语C#要完成本题要怎么做?


依旧是#两线程#、#打印奇偶数#, 我没找到C#中能多次对齐线程的能力, 于是使用两线程相互通知的方式。


volatile static int i = 0;
static AutoResetEvent are = new AutoResetEvent(true);
static AutoResetEvent are2 = new AutoResetEvent(false);
public static void Main(String[] args)
{
     Thread thread1 = new Thread(() =>
     {
          for (var i=0;i<=100;i++)
          {
             are.WaitOne();
             if (i % 2 == 0)
             {
                 Console.WriteLine(i + "== 偶数");
             }
            are2.Set();
          }
     });
     Thread thread2 = new Thread(() =>
     {
         for (var i = 0; i <= 100; i++)
         {
           are2.WaitOne();
           if (i % 2 == 1)
           {
               Console.WriteLine(i + "== 奇数");
           }
           are.Set();
         }
});
  thread1.Start();
  thread2.Start();
  Console.ReadKey();
}

注意:


  • • volatile:提醒编译器或运行时不对字段做优化(处于性能,编译器/runtime会对同时执行的线程访问的同一字段进行优化,加volatile忽略这种优化 )。


  • • Object-->MarshalByRefObject-->WaitHandle-->EventWaitHandle--->AutoResetEvent[3] 本次使用了2个自动重置事件来切换通知,由一个线程通知另外一个线程执行。


相关文章
|
7月前
|
Go 调度 开发者
CSP模型与Goroutine调度的协同作用:构建高效并发的Go语言世界
【2月更文挑战第17天】在Go语言的并发编程中,CSP模型与Goroutine调度机制相互协同,共同构建了高效并发的运行环境。CSP模型通过通道(channel)实现了进程间的通信与同步,而Goroutine调度机制则确保了并发任务的合理调度与执行。本文将深入探讨CSP模型与Goroutine调度的协同作用,分析它们如何共同促进Go语言并发性能的提升。
|
7月前
|
Go 开发者
Go语言并发模型概览:CSP模型解析
【2月更文挑战第17天】Go语言以其强大的并发处理能力在编程领域崭露头角。其中,CSP(Communicating Sequential Processes)模型作为Go语言并发模型的核心之一,在并发编程中发挥着至关重要的作用。本文将深入解析CSP模型的基本原理及其在Go语言中的应用,帮助读者更好地理解Go语言的并发编程特性。
|
7月前
|
安全 Go 开发者
Golang深入浅出之-Go语言中的CSP模型:深入理解并发哲学
【5月更文挑战第2天】Go语言的并发编程基于CSP模型,强调通过通信共享内存。核心概念是goroutines(轻量级线程)和channels(用于goroutines间安全数据传输)。常见问题包括数据竞争、死锁和goroutine管理。避免策略包括使用同步原语、复用channel和控制并发。示例展示了如何使用channel和`sync.WaitGroup`避免死锁。理解并发原则和正确应用CSP模型是编写高效安全并发程序的关键。
172 7
|
7月前
|
安全 Go 开发者
Golang深入浅出之-Go语言中的CSP模型:深入理解并发哲学
【5月更文挑战第1天】Go语言基于CSP理论,借助goroutines和channels实现独特的并发模型。Goroutine是轻量级线程,通过`go`关键字启动,而channels提供安全的通信机制。文章讨论了数据竞争、死锁和goroutine泄漏等问题及其避免方法,并提供了一个生产者消费者模型的代码示例。理解CSP和妥善处理并发问题对于编写高效、可靠的Go程序至关重要。
158 2
第五十二章 开发自定义标签 - Using csr %CSP.AbstractAtom Write Methods
第五十二章 开发自定义标签 - Using csr %CSP.AbstractAtom Write Methods
74 0
|
JavaScript 编译器 Go
第五十一章 开发自定义标签 - 使用%CSP.Rule方法
第五十一章 开发自定义标签 - 使用%CSP.Rule方法
84 0
|
SQL JavaScript 前端开发
第三十六章 使用 CSP 进行基于标签的开发 - 使用尽可能少的#server和#call调用
第三十六章 使用 CSP 进行基于标签的开发 - 使用尽可能少的#server和#call调用
133 0
|
JavaScript 前端开发 Go
第三十四章 使用 CSP 进行基于标签的开发 - Hyperevent例子
第三十四章 使用 CSP 进行基于标签的开发 - Hyperevent例子
122 0
|
前端开发 JavaScript 编译器
第三十三章 使用 CSP 进行基于标签的开发 - 使用Hyperevents #server和#call调用服务器端方法
第三十三章 使用 CSP 进行基于标签的开发 - 使用Hyperevents #server和#call调用服务器端方法
115 0
|
前端开发 程序员 Go
第三十二章 使用 CSP 进行基于标签的开发 - 服务器端方法
第三十二章 使用 CSP 进行基于标签的开发 - 服务器端方法
121 0