zoukankan      html  css  js  c++  java
  • 基于消息传递的并发模型:Actor和CSP的区别

    An object oriented language is a language with good support for objects.
    A concurrency oriented language has good support for concurrency.

    --Joe Armstrong

    两类通用并发模型:参考七周七并发模型

    • 共享内存型Shared Memory

      • 线程Threads
      • 锁Locks
      • 互斥l量Mutexes
    • 消息传送型(CSP和Actor模型)

      • 进程Processes
      • 消息Messages
      • 不共享数据(状态)No shared data

    重点介绍消息传送型的两种模型Actor和CSP(Communicating Sequential Process)的各项对比

    主要目的:除了常用的Python、Java等用的并发模型之外,还存在这么个东西

    先看两段代码

    代码示例对比

    使用Erlang代码和Go代码分别实现打印服务print_server,用来对比模型使用差异

    Actor模型-Erlang代码

    %%%-------------------------------------------------------------------
    %%% @author Suncle
    %%% @doc
    %%% print_server
    %%% @end
    %%% Created : 2017/12/18 14:53
    %%%-------------------------------------------------------------------
    -module(print_server).
    -author("Flowsnow").
    
    %% API
    -export([print_server/0, start_print_server/0, send_msg/2]).
    
    
    print_server() ->
      receive
        Msg ->
          io:format("print_server received msg: ~p~n", [Msg]),
          print_server()
      end.
    
    start_print_server() ->
      Pid = spawn(?MODULE, print_server, []),
      Pid.
    
    send_msg(Msg, Pid) ->
      Pid ! Msg,
      io:format("send_normal_msg: ~p~n", [Msg]).
    
    

    Erlang shell输出结果如下:

    1> c("print_server.erl").
    {ok,print_server}
    2> Pid = print_server:start_print_server().
    <0.39.0>
    3> print_server:send_msg("hello", Pid).
    send_normal_msg: "hello"
    print_server received msg: "hello"
    ok
    

    以上print_server使用的是最原始的Erlang语法实现的,也可以使用OTP gen_server原语实现更加清晰易懂

    CSP模型-Go代码

    print函数从channel读取消息并阻塞,直到主函数向channel写入hello消息

    package main
    
    import (
    	"fmt"
    	"time"
    )
    
    func main() {
    	c := make(chan string)
    	go print(c)
    	time.Sleep(1 * time.Second)
    	fmt.Println("main function: start writing msg")
    	c <- "hello"
    
    	var input string
    	fmt.Scanln(&input)
    }
    
    func print(c <-chan string) {
    	fmt.Println("print function: start reading")
    	fmt.Println("print function: reading: " + <-c)
    	time.Sleep(1 * time.Second)
    }
    

    输出结果如下:

    D:workspaceGo>go run print_server.go
    print function: start reading
    main function: start writing msg
    print function: reading: hello
    

    模型图对比

    Actor

    Actor1发送消息到Actor2的邮箱中,邮箱本质是队列,由Actor2消费

    CSP

    Process1在Channel的写入端添加消息,Process2在channel的读取端读取消息

    基本特性对比

    Actor

    1. 基于消息传递message-passing
    2. 消息和信箱机制:消息异步发送
    3. 保留可变状态但不共享
    4. 失败检测和任其崩溃
    5. 重点在于发送消息时的实体

    CSP

    1. 基于消息传递message-passing
    2. 顺序进程Sequential processes
    3. 通过channel同步通信Synchronous communication through channels
    4. 频道交替复用Multiplexing of channels with alternation
    5. 重点在于发送消息时使用的通道channel

    通信语义对比

    Actor

    Actor1等待消息并阻塞,直到Actor2发送消息给Actor1

    Actor2发送消息给Actor3,暂存在Actor3的Mailbox中,直到Actor3接受并处理

    CSP

    Process1读取channel因没有消息阻塞,直到Process2向该channel添加消息

    process2向channel添加消息并阻塞,直到Process3读取该channel消息

    Erlang实现简易银行账户

    使用Erlang原语,代码如下:

    使用OTP的gen_server,代码如下:

    Erlang小项目:IP数据库

    使用Erlang/OTP实现的IP数据库,可以根据IP查询到具体的国家省份等,代码如下:

    不一样的Erlang特性

    1. Let it crash思想:值得借鉴

    比如:执行算术异常崩溃

    1. 变量是不可变的,变量一旦赋予值就无法再改变:带来的好处就是没有可变状态,就不需要内存共享,也就不需要有锁
    2. Erlang进程之间的唯一交互方式就是消息传递:Erlang中没有像C++那样,进程间拥有多种不同的交互方式(管道、消息队列、存储共享等等)。

    FAQ

    为什么没有容量自动增大的缓冲区?

    即使现在有一个看上去永不枯竭的资源,总有一天这个资源还是会被用尽的。可能是因为时过境迁,当初的老程序现在需要解决更大规模的问题;也可能是存在一个bug,消息没有被及时处理,导致被堆积。如果没有思考缓冲区塞满时的对策,那么在未来的某个时间就有可能出现一个破坏性极强,隐蔽性极深且难以诊断的bug。最好的策略是在现在就思考如何处理缓存区被塞满的情况,将问题消灭在萌芽阶段。

    因此常用的缓存区类型有三种:阻塞型(blocking),弃用新值型(dropping),移出旧值型(sliding)

    Python有什么消息传递并发模型?

    Actor模型pykka:https://github.com/jodal/pykka

    CSP模型pycsp:https://github.com/runefriborg/pycsp/wiki/Getting_Started_With_PyCSP


    图片均来源于here


    参考:


    记得帮我点赞哦!

    精心整理了计算机各个方向的从入门、进阶、实战的视频课程和电子书,按照目录合理分类,总能找到你需要的学习资料,还在等什么?快去关注下载吧!!!

    resource-introduce

    念念不忘,必有回响,小伙伴们帮我点个赞吧,非常感谢。

    我是职场亮哥,YY高级软件工程师、四年工作经验,拒绝咸鱼争当龙头的斜杠程序员。

    听我说,进步多,程序人生一把梭

    如果有幸能帮到你,请帮我点个【赞】,给个关注,如果能顺带评论给个鼓励,将不胜感激。

    职场亮哥文章列表:更多文章

    wechat-platform-guide-attention

    本人所有文章、回答都与版权保护平台有合作,著作权归职场亮哥所有,未经授权,转载必究!

  • 相关阅读:
    [Baltic2013]ballmachine BZOJ3133
    [Jxoi2012]奇怪的道路 BZOJ3195 状压DP
    [Baltic 2011]Lamp BZOJ2346
    可并堆
    [Jsoi2016]最佳团体 BZOJ4753 01分数规划+树形背包/dfs序
    点分治
    J2EE WEB应用架构分析
    {经典}springmvc+mybatis+restful+webservice Jeesz分布式架构
    深入Spring Boot:那些注入不了的 Spring 占位符 ( ${} 表达式 )
    G1 垃圾收集器之对象分配过程
  • 原文地址:https://www.cnblogs.com/CHLL55/p/14154106.html
Copyright © 2011-2022 走看看