当前位置: 首页 > 科技观察

三分钟掌握Actor和CSP模型

时间:2023-03-15 15:21:53 科技观察

go的CSP模型传统的多线程共享内存(ShareMemory)模型使用lock、condition等同步原语来强制执行进程的执行顺序。Actor模型是一种基于消息传递的并发模型,强调Actor的工作实体,每个Actor决定消息传递的方向(要传递的ActorB),通过消息传递形成管道。本文现在要记录的是另一种基于消息传递的并发模型:CSP(communicatingsequentialprocess)。在CSP模型中,worker之间不直接通信,强调通道在消息传递中的作用,不寻求形成管道。消息的发送者和接收者通过这个通道松耦合。发送方不知道哪个接收方消费了他的消息,接收方也不知道哪个发送方发送了消息。go'schannelgo'schannel[1]是golang协程同步通信的原生方式。和map、slice一样,channel也是通过make的内置函数进行初始化,返回一个引用,可以看作是一个常量指针[2]。两种channel:1.Unbufferedchannel:只有读写端都准备好了才能通信(如果有一方没准备好就阻塞)。这种方法可用于在没有显式锁或条件变量的情况下同步goroutines。2.有buffer通道:可以不阻塞,只有buffer满了才会阻塞写入;只有当缓冲区为空时,读取才会被阻塞。go频道就暂时停在这里。让我们用上面的背景来做一个有趣的面试题。两个线程依次打印0到100?不懂算法,思维弱智:#两身表#,#打印奇数/偶数#,我先复现这两个标签。将每个循环与Go无缓冲通道的同步阻塞功能对齐。packagemainimport("fmt""strconv""sync")varwgsync.WaitGroupvarch1=make(chanstruct{})funcmain(){wg.Add(2)gofunc(){deferwg.Done()for我:=0;我<=100;i++{ch1<-struct{}{}ifi%2==0{//甚至fmt.Println("g0"+strconv.Itoa(i))}}}()gofunc(){deferwg.Done()对于我:=0;我<=100;i++{<-ch1ifi%2==1{//oddfmt.Println("g1"+strconv.Itoa(i))}}}()wg.Wait()}问题解决:两个协程都执行0到100次循环,但是无论哪个线程跑得快,每次循环输出时都会同步对齐,每次循环时只输出一个奇/偶值,所以不需要考虑两个协程的顺序开始了。想着我老土的语言C#,我该怎么做才能完成这道题呢?还是#twothreads#,#printingoddevennumber#,我在C#中没有找到多次对齐线程的能力,所以我使用了两个线程相互通知的方法。volatilestaticinti=0;staticAutoResetEventare=newAutoResetEvent(true);staticAutoResetEventare2=newAutoResetEvent(false);publicstaticvoidMain(String[]args){Threadthread1=newThread(()=>{for(vari=0;i<=100;i++){are.WaitOne();if(i%2==0){Console.WriteLine(i+"==even");}are2.Set();}});线程thread2=newThread(()=>{for(vari=0;i<=100;i++){are2.WaitOne();if(i%2==1){Console.WriteLine(i+"==奇数");}are.Set();}});thread1.Start();thread2.Start();Console.ReadKey();}注意:volatile:警告编译器或运行时系统不要优化该字段(为了性能,编译器/运行时会优化同时执行的线程访问的同一个字段,加上volatile忽略这个优化)。Object-->MarshalByRefObject-->WaitHandle-->EventWaitHandle--->AutoResetEvent[3]这次用两个自动重置事件来切换通知,一个线程通知另一个线程执行。参考链接[1]go通道:https://www.runoob.com/w3cnote/go-channel-intro.html[2]常量指针:https://zhuanlan.zhihu.com/p/133225100[3]AutoResetEvent:https://docs.microsoft.com/en-us/dotnet/api/system.threading.autoresetevent?view=net-6.0