语言是技术栈的基础,语言中往往体现了重要的设计思想。erlang和go是两种比较特殊的我喜欢的语言,erlang是面向线程的反映世界的语言,主要是函数式;而go则是集c、c++、java、haskel等语言长处为一体的语言,本文主要对照一下两种语言并发通信的原理。
轻量级线程
erlang和go都实现了用户态的调度,都是轻量级协程,go的调度见《go runtime和java jvm》一文。
actor
actor是什么,actor就是消息的方式进行通信,对于每个erlang线程,都有一个消息队列用于存储消息。
-module(tut15).
-export([start/0, ping/2, pong/0]).
ping(0, Pong_PID) ->
Pong_PID ! finished,
io:format("ping finished~n", []);
ping(N, Pong_PID) ->
Pong_PID ! {ping, self()},
receive
pong ->
io:format("Ping received pong~n", [])
end,
ping(N - 1, Pong_PID).
pong() ->
receive
finished ->
io:format("Pong finished~n", []);
{ping, Ping_PID} ->
io:format("Pong received ping~n", []),
Ping_PID ! pong,
pong()
end.
start() ->
Pong_PID = spawn(tut15, pong, []),
spawn(tut15, ping, [3, Pong_PID]).
例如这段代码, 启动了2个erlang线程,pong线程启动的时候记录pid,传递给ping线程,pid ! message表示把消息传递给pid的线程,而消息处理用receive来处理,就是一个典型的消息队列处理,所以整个erlang的吞吐效率非常高。
go cas
go的cas是强调通信信道,可以参照Go channel 实现原理分析 - 简书 (jianshu.com)
type hchan struct {
qcount uint // total data in the queue 当前队列里还剩余元素个数
dataqsiz uint // size of the circular queue 环形队列长度,即缓冲区的大小,即make(chan T,N) 中的N
buf unsafe.Pointer // points to an array of dataqsiz elements 环形队列指针
elemsize uint16 //每个元素的大小
closed uint32 //标识当前通道是否处于关闭状态,创建通道后,该字段设置0,即打开通道;通道调用close将其设置为1,通道关闭
elemtype *_type // element type 元素类型,用于数据传递过程中的赋值
sendx uint // send index 环形缓冲区的状态字段,它只是缓冲区的当前索引-支持数组,它可以从中发送数据
recvx uint // receive index 环形缓冲区的状态字段,它只是缓冲区当前索引-支持数组,它可以从中接受数据
recvq waitq // list of recv waiters 等待读消息的goroutine队列
sendq waitq // list of send waiters 等待写消息的goroutine队列
// lock protects all fields in hchan, as well as several
// fields in sudogs blocked on this channel.
//
// Do not change another G's status while holding this lock
// (in particular, do not ready a G), as this can deadlock
// with stack shrinking.
lock mutex //互斥锁,为每个读写操作锁定通道,因为发送和接受必须是互斥操作
}
// sudog 代表goroutine
type waitq struct {
first *sudog
last *sudog
}
其中channel的实现特别需要留意,消息的存储在buf中,这里是一个环形队列的设计,使用环形队列控制大小和发送、消费的机制;使用channel的发送队列保存在recvq,消费队列保存在sendq中,了解了这些基本就可以推测出channel的工作机制了,和生产者消费者就是一个原理。
小结
ACTOR和CAS是非常有意思的两种线程通信机制,各有所长,你更喜欢哪种设计?其中akaka就是jvm系列的actor。








网友评论