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

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/

发布了1 篇原创文章 · 获赞 1 · 访问量 79

猜你喜欢

转载自blog.csdn.net/qq_32702033/article/details/104415434