并发机制:CSP vs Actor模型以及Golang实现

标签: Go  go  并发编程

CSP & Actor Model

本文将简单介绍CSP和Actor模型俩流行的并发机制,并比较他们的优缺点,并通过Golang中CSP并发机制实现FutureTask.并行机制有很多像是多线程,CSP,Actor等等.拿多线程来说,就有诸多问题,譬如:死锁,可扩展性差,共享状态.就像共享状态会产生很多问题,它涉及到内存的变化。只有一个进程发生变化没问题。但如果有多个进程共享和修改相同的数据,这将非常糟糕.为解决这些问题,提出了很多解决方法呢.比如,CSP和ActorModel.

如下是一些编程语言,以及它们相应的并发机制:

  • Actors Model — Erlang, Scala, Rust
  • CSP — Go-lang
  • 多线程 — Java, C#, C++

CSP

CSP(Communicating Sequential Processes)是依赖于一个通道channel完成两个通信实体之间协调的并发模型。它基于不共享内存的消息传递.

Go语言哲学就是不通过共享内存进行通信;而是,通过通信进行共享内存。

go语言中的unbuffered Channel:

  • 当在程序代码内丢了一个值到 channel,这时候 main 函数就需要等到一个 channel 值被读出来才会结束.
    在这里插入图片描述

BufferedChannel:

  • buffered channel 就是只要有容量,你都可以塞值进去,但是不用读出来没关系
    在这里插入图片描述

异步返回:利用Golang中的CSP并发机制实现FutureTask

熟悉Java的人对FutureTask有所了解.通俗来讲就是当执行一个函数或一个task的时候,并不需要马上知道它的结果,在需要结果时get结果.如果结果还没有出来,就继续阻塞在那里;如果等到了结果就继续向下执行.这样做的好处可以提高程序运行的效率,因为在执行task的时候,可以去执行其他任务.FutureTask在Java中的实现代码如下:

    private static FutureTask<String> service() {
        FutureTask<String> task = new FutureTask<String>(()->"Do something");
        new Thread(task).start();
        return task;
    }
    FutureTask<String> ret = service();
        System.out.println("Do something else");
        System.out.println(ret.get();


下面我们来看一看如何用Golang中CSP机制实现FutureTask:

package csp
import (
  "fmt"
  "testing"
  "time"
)
func service() string{
  time.Sleep(time.Millisecond * 50)
  return "Done"
}
func otherTask(){
  fmt.Println("working on something esle")
  time.Sleep(time.Millisecond * 100)
  fmt.Println("Task is done.")
}
//TestService()直接用了串行运行.耗时将是service()和otherTask()之和.
func TestService(t *testing.T){
  fmt.Println(service())
  otherTask()
}


func AsyncService() chan string{
  // retCh := make(chan string)     ①
  retCh := make(chan string, 1)   //②
  go func(){
    ret := service()
    fmt.Println("Returned result")
    retCh <- ret
    fmt.Println("Service exited")
  }()
  return retCh
}

func TestAsynService(t *testing.T){
  retCh := AsyncService()
  otherTask()
  fmt.Println(<-retCh)
  time.Sleep(time.Second * 1)
}


使用Channel,即使用示例代码中①,运行结果如下:

=== RUN   TestService
Done
working on something esle
Task is done.
--- PASS: TestService (0.16s)
=== RUN   TestAsynService
working on something esle
Returned result
Task is done.
Done
Service exited
--- PASS: TestAsynService (1.10s)
PASS
ok      command-line-arguments  5.099s

使用BufferedChannel,即使用示例代码中②,运行结果如下:

=== RUN   TestService
Done
working on something esle
Task is done.
--- PASS: TestService (0.15s)
=== RUN   TestAsynService
working on something esle
Returned result
Service exited
Task is done.
Done
--- PASS: TestAsynService (1.10s)
PASS
ok      command-line-arguments  3.411s

优点:

  • CSP允许通过使用通道避免生产者和消费者之间的耦合;他们不需要了解对方。
  • 在CSP中,消息是按照它们被发送的顺序发送的。

缺点:

  • CSP通常用于单机,它不如分布式编程的Actor模型那么好。

CSP不同于Erlang,Scala中的Actor Model

Actor Model

Actor是并发原语,简单来讲,就是两个消息实体之间通过发送消息进行协调.

在这里插入图片描述

CSP和Actor Model最主要的区别有两点:

  • 和Actor的直接通讯不同,CSP模式则是通过Channel进行通讯的,更松耦合一些。
  • Go中channel是有容量限制并且独立于处理Goroutine,而如Erlang, Actor模式中的mailbox容量是无限的,接收进程也总是被动地处理消息。

优点:

无死锁

没有手动多线程编程和共享内存意味着没有显式锁的几乎无死锁同步。

容错性

actor之间的隔离性导致actor失败不会影响其他actor,监控者可以对自然失败的actor做直接处理而不会带来连锁问题。这让“自愈系统”成为可能,就是说一个actor异常后,监控者可以恢复一致性,可能以初始状态重起actor。

分布式

Actor模型被用来解决分布式程序的问题而设计,因此它非常适合跨多台机器扩展.

缺点:

如果系统需要使用共享状态,或者需要保证按特定顺序执行,actor可能无法工作。

CSP 和 Actor Model的对比

  • 这两个模型都基于消息传递:发送方发送消息,接收方接收消息。在这两个模型中,接收器是同步的。当它准备好监听消息时它就会阻塞,直到它收到消息

  • CSP是完全同步的。通道写入器必须阻塞,直到通道读取器读取为止。这种基于阻塞的机制的优点是,一个通道只需要保存一条消息。

  • 用Actor发送是异步的。无论读取器是否准备好从mailbox取出,消息发送方都不会阻塞,而是将消息放入通常称mailbox的队列中。

  • 在CSP进程中,使用通道进行通信。程序可以创建并传递它们作为第一类对象。参与者有一个地址系统和收件箱。每个进程只有一个地址。

  • 在CSP中,发送和接收操作可能会阻塞。在Actor模型中,只有接收操作可能阻塞。

  • 在CSP中,消息是按发送顺序发送的,而在Actor模型中则不是这样,系统可能根本无法传递某些消息。

  • 到目前为止,CSP模型在一台机器上工作得最好,而actor模型很容易跨多台机器扩展。

总结

总之:Actor更适合于分布式系统。由于CSP的阻塞特性,很难在多台机器/运行时之间使用它们。

CSP和Actor Model最主要的区别有两点:

  • 和Actor的直接通讯不同,CSP模式则是通过Channel进行通讯的,更松耦合一些。
  • Go中channel是有容量限制并且独立于处理Goroutine,而如Erlang, Actor模式中的mailbox容量是无限的,接收进程也总是被动地处理消息。

参考文献:

[1].Introduction to Concurrency Models with Ruby. Part II.https://engineering.universe.com/introduction-to-concurrency-models-with-ruby-part-ii-c39c7e612bed.

[2].Parallelism models. Actors vs CSP vs Multithreading.https://medium.com/@1_00794/parallelism-models-actors-vs-csp-vs-multithreading-f1bab1a2ed6b

[3].The actor model in 10 minutes.https://www.brianstorti.com/the-actor-model/

版权声明:本文为qq_32702033原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/qq_32702033/article/details/104415434

智能推荐

并发机制底层实现整理

1. 缓存一致性问题             硬件内存架构 现代计算机一般都有 2 个以上 CPU,而且每个 CPU 还有可能包含多个核心。因此,如果应用是多线程的话,这些线程可能会在各个 CPU 核心中并行运行。 在 CPU 内部有一组 CPU 寄存器,也就是 CPU 的储存器。 CPU 操作寄存器的速度要比操作计算机主存快的多。 在主存和 CPU 寄存器之间还存在一个 CPU 缓存,...

Go语言 | CSP并发模型与Goroutine的基本使用

本文始发于个人公众号:TechFlow,原创不易,求个关注 今天是golang专题的第13篇文章,我们一起来聊聊golang当中的并发与Goroutine。 在之前的文章当中我们介绍完了golang当中常用的使用方法和规范,在接下来的文章当中和大家聊聊golang的核心竞争力之一,并发模型与Goroutine。 我们都知道并发是提升资源利用率最基础的手段,尤其是当今大数据时代,流量对于一家互联网企...

VS Code golang 断点调试

实现效果 安装 delve windows go get -u github.com/go-delve/delve/cmd/dlv linux 方式一: go get -u github.com/go-delve/delve/cmd/dlv 方式二 注意: 若果你go版本为1.5需要设置GO15VENDOREXPERIMENT=1 OSX 执行上述代码前,确保你电脑上有编译工具 设置 launch...

IDEA下Spring项目报错-could not autowire. no beans of“” type found

把一个eclipse的项目导入到IDEA,发现项目打开就报错:-could not autowire. no beans of“” type found。 在eclipse下面没有问题 项目编译和运行没有问题。 原因 网上搜索了一下原因。 spring auto scan配置,在编辑情况下,无法找不到对应的bean,于是提示找不到对应bean的错误。常见于mybatis的m...

猜你喜欢

!HTML制作APP注册页面,利用form等标签,达到想要的结果,以帮助自己了解html的排版和页面的问题,我们的css中的代码。对于页面有着至关重要的效果,如果出现问题,就要更加小心,其中的问题,

首先建立一个基本框架,已搭建根本的服务 然后我们深刻体会其中的知识点。 在我们建立表单的时候,一定要注意的是,对于一些选项,只能选择一个,不然就会出像笑话了。 比如:性别,等,一个不可以出现两种性别,特殊不在讨论范围,大众的来说,不可以出现这样的错误。 以下是css3 的代码。我们是要把其中的代码代表意思搞懂,不如也是一个。“码农” 效果如下: 今天的文章就到这里,有更好的...

iOS 从app中分享出小程序

1、小程序缩略图的图片比例是:5:4,图片在分享过程中会被微信进行二次压缩,如果出现图片模糊的情况,可以修改成一张稍微高质量的图片,但是大小要小于128K 2、需要小程序的原始ID:   gh_xxxxxxxx 一定是gh开头的 3、需要path:pack-xxxx/xxxxx/xxxxxx  类似这种 4、使用微信分享方法,我这里用的是原生微信分享,没有使用第三方 ...

grbl脱机控制器

grbl脱机控制器 1年前因为研究自动写字机,所以渐渐萌生出做一台cnc控制器的想法,因为原来自己也研究过自动化控制,所以对于步进电机的控制还算熟悉,但由于精力的原因没有整出一个完整的控制框架,今年正好疫情严重导致自己也没啥事,所以花点时间做了一整套的东西。 然后还要说明的是,标题虽然是是grbl的脱机控制器,但实际和grbl一点关系都没有,做个标题党,吸引下点击率,这套控制系统从头到尾都是自己一...

leetcode24:两两交换链表中的节点(java实现)

    需求 给定一个链表,两两交换其中相邻的节点,并返回交换后的链表。 你不能只是单纯的改变节点内部的值,而是需要实际的进行节点交换。   示例: 给定 1->2->3->4, 你应该返回 2->1->4->3. 分析 奇数&偶数:链表整体长度为偶数时可以两两进行,奇数时最后一个数位置不变 具体实现:链表反转位置,并且其前...

pycharm+pyqt5+QtDesigner+pyUIC第一个pyqt5程序

安装pyqt5和pyqt5-tools 在tools中添加QtDesigner和PyUIC QtDesigner在"./Lib/site-packages/pyqt5_tools/Qt/bin"下,具体视python安装目录而定。PyUIC目录为"./Scripts/pyuic5.exe"。 在pycharm中,File->Settings->T...