专栏首页职场亮哥基于消息传递的并发模型

基于消息传递的并发模型

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:\workspace\Go>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

参考:

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • CentOS7-Nginx配置Let's-Encrypt-SSL证书

    为http站点添加https支持,需要从证书发行机构获取SSL/TLS 证书。常见的免费证书有两种:

    职场亮哥
  • Python异常处理

    Python用异常对象来表示异常情况。遇到错误后,会引发异常。如果异常没有处理或捕捉,程序就会用traceback终止程序的执行,如果是在多线程程序中,则会终止...

    职场亮哥
  • Python函数定义及参数详解

    首先我们来创建一个函数,输出指定范围内的斐波拉契数列(Fibonacci series)。

    职场亮哥
  • 数据类型补充

    另外还有一种未被提到的数据类型为虚数complex在python中虚数为5j来表示

    小小咸鱼YwY
  • 使用神经网络解决拼图游戏

    在一个排列不变性的数据上神经网络是困难的。拼图游戏就是这种类型的数据,那么神经网络能解决一个2x2的拼图游戏吗?

    deephub
  • Sentinle集群流控【源码笔记】

    本文从集群流控概览入手,按照概览的步骤逐步分析各个步骤的源码实现过程。由于集群流控中token server可以是独立部署也可以是使用内嵌模式(即集群应用中的其...

    瓜农老梁
  • nginx 禁止ip直接访问,防止恶意解析

    找到 nginx 的默认配置文件 nginx.conf 编辑文件找到 默认的80 server

    Alone88
  • python 文件操作读、写、追加的区别

    a+模式下,虽然能读取,但指针已到最后,直接read,不会出内容,可以用seek()重置指针

    py3study
  • 如何配置Spring Boot Tomcat

    Spring Boot Web应用程序默认包含预配置的嵌入式Web服务器。但在某些情况下,我们要修改默认配置以满足自定义要求。

    乱敲代码
  • SSM 单体框架 - 前端开发:用户权限控制,Nginx 和项目部署与发布

    actions.js 中的 createToken 方法发送登录请求,进行登录的代码

    RendaZhang

扫码关注云+社区

领取腾讯云代金券