两种常用的并发模型:CSP和Actor

深入解析actor 模型(一): actor 介绍及在游戏行业应用 1 介绍 1.1 什么是actor 对于刚接触actor的我,第一感觉就像redis一样,每个actor就是一个redis 实例,都有自己消息队列,actor相互通信通过将消息发给对方,消息发送进对方的消息队列,等待对方线程处理。来看看我们之前做项目的痛点。 游戏服务器通常分为多个服,每个服上有多个玩家。假设玩家与玩家数据交互操作,这时怎么避免数据竞争?两种解决方案: 1、将数据写入redis 首先redis效率高,也是单线程模型,不存在数据竞争,但是也有它的不足之处,操作redis 会受网络影响 阅读详情

概述

现如今的机器大都是多核的CPU架构,为了充分利用计算机的资源,我们要了解一些并发编程的思想。

大家应该都了解传统的并发编程模式,多线程编程。
传统的多线程编程实际上是使用的ShreadMemory的方式来推动程序的前进。
为什么说new一个thread的方式是共享内存呢?
有并发的地方就有竞争,传统多线程的并发模式使用locks(锁),condition variable(条件变量)等同步原语来强制规定了进程的推进顺序,而这些同步原语本质上都是使用了在各个线程都可见的锁来实现,有一种全局变量的味道。(少数由硬件指令直接支持的除外,例如atomic_int。
那么除了直接控制thread,使用shared memory之外我们还有什么别的并发模型吗?

答案是有的~
今天我要分享的CSP和Actor模型都是基于消息传递的。(Message Passing)

CSP

CSP的是Communicating Sequential Processes (CSP)的缩写,翻译成中文是顺序通信进程,不过这个名字比较拗口,下文将用CSP来代替。
CSP的核心思想是多个线程之间通过Channel来通信(对应到golang中的chan结构),有点像是管道的概念。(Pipe)

在这里插入图片描述

Actor

Actor模式有一点类似面向对象模型,世界上所有的东西都被命名为Actor。
单个Actor会拥有一些状态,比如为名字是cat的Actor可能被描述为:

name : cat
age : 3
type : British shorthair
color : white
....

到此为止好像和对象object没有什么不同,但是Actor不会给外界提供任何的行为接口.
比如cat.Move()这是很自然的面向对象的写法,在Actor是不被允许的。
每一个Actor的属性绝不对外暴露,想和外界进行通信必须发送message,所以每个Actor自身都有一个邮箱。

在这里插入图片描述

无论是CSP还是Actor模型,他们都完完全全贯彻了一句至理名言:

Don't communicate by sharing memory; share memory by communicating. (R. Pike)

CSP :Goroutine

golang中的goroutine我们可以理解为是一个thread,但是它非常精简,调度的开销也非常小。
goroutine之间的通信使用名为chan的数据结构,对应CSP模型中的channel。
goroutine的使用很简单,仅需要关键词go即可启动一个goroutine,不同的goroutine之间使用channel进行通讯,这都是很基本的用法,就不背语法书了。
关于goroutine,还是想多聊一聊golang是如何调度goroutine的。

Go的调度器内部有三个重要的结构:M,P,S。
M:代表真正的内核OS线程,真正干活的人
G:代表一个goroutine,它有自己的栈,指令集信息(要执行的指令)和其他信息(正在等待的channel等等),调度的单位。
P:代表调度的上下文,可以把它看做一个局部的调度器,使go代码在某个M上跑

在这里插入图片描述

当go运行起来的时候,大致是下图的样子:

在这里插入图片描述

简单解释一下:
图中的两个M表示当前go运行的机器上有两个线程可以让我们使用。
P是goland的调度上下文,它必须运行在某个M上,实际上就类似:
new Thread(P.run())
P上挂着好几个goroutine :
蓝色的G表示当前P正在调度的goroutine,此时相当于把蓝色的G扔到了M上。
灰色的G表示正在等待P调度的goroutine,轮到他们的时候就会被扔到M上。(如何公平的调度灰色的G?)
目前来看,P好像是多余的,我直接想办法把G扔到M上就好了,为何还要有一个P这样的中间层的。
当然P很有必要,如果某个线程M被阻塞了,那么P可以被扔到其他的线程上,去合理的调度它挂着的G。

在这里插入图片描述

这个图表示的就是M0被阻塞了,转而把P挂到了M1上。
可以看到M0此时有一个G0在运行,这是啥意思…
我们在具体一点吧:

G0
n = read(fd, buf, size)
print(n)

G0之前在P上挂着,开心的在M0上运行(蓝色的G0),此时G0调用了系统调用read,显然G0被阻塞了。
golang为了充分利用cpu资源,不让那些被排队的goroutine浪费时间,P挂到了M1上。
那么问题来了,如果read完了,系统调用结束,那么该打印n了,可是这时候没有P了,怎么办?
golang会维护一个全局队列,把G0放到一个全局队列了,然后M0就去sleep了。
所有的P会周期性的检查全局队列里的G,否则这些G就都饿死了。
由此可见,P是很有必要的。
还有很神奇的一点,P可以“偷“任务。
考虑一种情况:

P1身上的G不巧都是和网络IO有关,运行的非常缓慢。
P2身上的G都是一些比较快的运算函数,他很快就完成了,那么他就会尝试从P1那里偷一些G来运行。

channel的结构

type hchan struct {
	qcount   uint           // 缓存当前包含数据个数
	dataqsiz uint           // 缓存容量
	buf      unsafe.Pointer // 缓存指针,缓存是一个循环数组,数据大小为dataqsiz
	elemsize uint16   // 
	closed   uint32   // channel开关状态
	elemtype *_type   // 数据类型  
	sendx    uint   // send index
	recvx    uint   // receive index
	recvq    waitq  // list of recv waiters(阻塞的接受goroutine队列)
	sendq    waitq  // list of send waiters(阻塞的发送goroutine队列)
	lock mutex
}

// 阻塞goroutine队列
type waitq struct {
	first *sudog
	last  *sudog
}

// goroutine的封装(公用数据结构)
type sudog struct {
	g          *g
	selectdone *uint32 // CAS to 1 to win select race (may point to stack)
	next       *sudog
	prev       *sudog
	elem       unsafe.Pointer // 发送goroutine为发送变量地址,接收goroutine反之
	......
}

这里可能有点抽象,上一个图更直观一点:

ch := make(chan int , 10 ) ,对应的runtime中的实现是:

func makechan(t *chantype, size int64) *hchan

该函数的主要作用就是从堆上分配内存,当然和c的malloc的有些不同,可以大略看一下:

	var c *hchan
	switch {
	case size == 0 || elem.size == 0:
		// Queue or element size is zero.
		c = (*hchan)(mallocgc(hchanSize, nil, true))
		// Race detector uses this location for synchronization.
		c.buf = unsafe.Pointer(c)
	}

注意使用的是mallocgc,go会在合适的时候gc掉这块内存

channel的读写

var val int = 666
ch := make(chan int , 10)
ch <- val

这是我们在go中向channel写入数据的结构的方法,对应到:

func chansend(c *hchan, ep unsafe.Pointer, block bool, callerpc uintptr) bool

参数c就是实际对应的chan
参数ep是变量val的地址

0.各种参数的有效性的校验
1.获取channel上的锁,如果是已经关闭的channel,会释放锁否则继续逻辑:

	lock(&c.lock)

	if c.closed != 0 {
		unlock(&c.lock)
		panic(plainError("send on closed channel"))
	}

2.获取channel的recv队列,dequeue出的sg就是上文中的sudog,向等待的这个channel的goroutine会发送刚才的val(在这里就是ep)

	if sg := c.recvq.dequeue(); sg != nil {
		// Found a waiting receiver. We pass the value we want to send
		// directly to the receiver, bypassing the channel buffer (if any).
		send(c, sg, ep, func() { unlock(&c.lock) }, 3)  // 发送val给sg(goroutine),sg在等待c
		return true
	}
  1. 如果没有等待该channel的goroutine,看一下channel的剩余缓存是不是够大,如果可以,把数据放进去
	if c.qcount < c.dataqsiz { //缓存中的数据个数 < 缓存的容量
		// Space is available in the channel buffer. Enqueue the element to send.
		qp := chanbuf(c, c.sendx)
		if raceenabled {
			raceacquire(qp)
			racerelease(qp)
		}
		typedmemmove(c.elemtype, qp, ep)//把数据放进去
		c.sendx++
		if c.sendx == c.dataqsiz {
			c.sendx = 0
		}
		c.qcount++
		unlock(&c.lock)
		return true
	}

4.缓存不够大,channel没有办法在塞数据了, 自身会因此阻塞,此时调度器会执行别的goroutine
在让出线程之前,会new一个goroutine出来,把多的数据放到这个goroutine上,加入到等待队列。

// Block on the channel. Some receiver will complete our operation for us.
	gp := getg()
	mysg := acquireSudog()
	mysg.releasetime = 0
	if t0 != 0 {
		mysg.releasetime = -1
	}

打包数据,发送等待队列

	mysg.elem = ep
	mysg.waitlink = nil
	mysg.g = gp
	mysg.isSelect = false
	mysg.c = c
	gp.waiting = mysg
	gp.param = nil
	c.sendq.enqueue(mysg) //把goroutine加入到sendq
	goparkunlock(&c.lock, "chan send", traceEvGoBlockSend, 3)

这样可能太抽象了,我们举个最简单的生产者消费者例子:

//生产者
func main(){
	//1.
    ch := make(chan Data, 4)
    //2.
    for _, task := range  {
        ch <- task
    }
    //3.
    for i := 0; i< 10; i++ {
        go consumer(ch)
    }
}

// 消费者
func consumer(ch chan Data){
    for {
        //收取任务并处理
        data := <- ch
        process(data)
    }
}

main的goroutine是生产者,以G1代替
consuemr的goroutine是消费者,以G2代替

1.初始化chan数据,创建hchan结构体。
hchan.buf指向一个大小为4的数组,并且hchan.sendx、hchan.recvx置0,hchan.dataqsiz置4。
2.发送数据
G1向channel发送数据,把要发送的数据拷贝到buf里,hchan.sendx++。(该过程需要加锁)
3.接受数据
G2从channel接受数据,将接受的数据拷贝到buf里,hchan.recvx++。(该过程需要加锁)
4.特殊情况
G1向chan发数据,chan的buf满了,会怎么样?
此时,runtime把G1和要发的数据打包成sudog,状态设置为等待,加到chan的sendq阻塞队列中,然后执行goparkunlock()把当前线程让出。
G2从chan中取出一条数据的时候,chan的buf有空了,然后从chan的sendq取出G1来执行。

Actor

Actor模型在web后端应用的不是很广泛,只有一些比较小众的语言天然支持这种编程范式(erlang),但是在游戏后端算是非常常用的编程范式。
Actor模型写起来比较舒服,因为你无需担心多线程的问题,只要是Actor自身的状态是不会被外界直接改变,都是通过handlemsg的方式来改变。

大部分语言都不原生支持Actor模型,这里以C系的语言为例,给大家分享如何来实现Actor模型。

0.ActorBase -> Actor的基类
每一个线程中有一个Actor,充分利用CPU资源。

ActorBase
{
	id  -> Actor的Id,用于区分不同的Actor
	status -> Actor的状态
	properties -> Actor的各种属性
	mailbox -> Actor的邮箱 (线程安全)
	recvmsg(msg) -> 接受消息的接口
	run() 
	{
		while(msg = get_from_mailbox()) 
		{
			handlemsg(msg)
		}
	}
}

1.GlobalActorController -> 全局的Actor调度器

GlobalActorController
{
	list<ActorBase> actor_list -> 全部actor的容器
	threadpool -> 根据某种调度策略,遍历actors,调用actor.run()
	sendmsg(send_actor_id, recv_actor_id, msg) -> 发送消息
	broadcastmsg(send_actor_id, recv_actor_id_list, msg)	-> 广播消息
}

这个代码部分可能有些抽象,让我们举个例子:

游戏中常见的商城功能,我们定义一个

ShopMallActor : extend from ActorBase
商城Actor管理了所有在商城中出售的商品,它维护一个出售的物品的list
list<shop_item> shop_item_list

然后所有的玩家都在某个具体的场景中,我们定义一个

SceneActor : extend from ActorBase
场景Actor管理了所有在这个场景中的玩家,它维护一个玩家的list
list<player> player_in_scene_list;

显然商城actor和场景actor没有任何关系,把他们看做是两个不同的actor添加到我们的GlobalActorController的actor_list中,扔到线程池中。

那么如果玩家想从商城里买东西应该是怎样的呢:
1.player.sendmsg(ShopActorId, buy_msg)
2.场景actor就会把这个buy_msg交付给GlobalActorController, 调用sendmsg(SceneActorId, ShopActorId, buy_msg)转发给ShopMallActor
3.商城Actor在自己的run方法里取出msg,发现了buy_msg,去handle(buy_msg), 在条件检测完毕后,发回msg给SceneActor
SceneActor通过某种策略找到到底哪个玩家发送的这个buy_msg(比如发buy_msg的时候在msg中带着player的uid),将物品发还给玩家

CSP网络结构实战 - 降低计算量的特征融合方式 CSPNet通过引入梯度变化的整合机制,从而降低推理过程中的计算量。其核心思想是将输入切分,通过新的特征融合方式来降低计算瓶颈和内存成本,从而在轻量化的同时保持模型准确性。CSPNet可以与多种经典网络结构如ResNet、ResNeXt和DenseNet结合使用。通过实验我们可以发现,在引入CSP结构后,模型参数量显著减少,计算量降低,同时准确性能够得到保证。然而,由于在每个阶段中增加了额外的卷积层,模型大小有所增加。对于不同数据集和网络结构,可以进一步尝试CSP的应用,例如在ResNet等网络中的应用。 阅读详情

相关推荐

基于消息传递的并发模型: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

职场亮哥 704

三分钟掌握Actor和CSP模型

点击上方蓝字进行关注前文传送门:《三分钟掌握共享内存模型和 Actor模型》, 一直想比较Actor模型与golang的CSP模型,经过一段时间的实战记录了本文。ActorvsCSP模型•传统多线程的的共享内存(ShareMemory)模型使用lock,condition等同步原语来强行规定进程的执行顺序。•Actor模型,是基于消息传递的并发模型, 强调的是...

qq_30236895的博客 1805

actor:Actor模型的C ++实现

演员 用于构建事件驱动的异步系统的通用框架,旨在利用现代多核处理器体系结构。 它非常喜欢“标记事件驱动的体系结构”(SEDA)事件驱动器模型来进行流水线事件处理。 该系统非常适合构建IO密集型,对延迟敏感的应用程序(例如数据库,文件系统等),这些应用程序利用SSD等高吞吐量设备并支持10+ Gbps之类的高端通信硬件。

【go语言】CSP并发机制与Actor模型

多线程共享内存模型是一种并发编程模型,其中多个线程在同一个进程的地址空间中。这种模型允许多个线程相同的数据结构,但也引入了一些潜在的问题,其中最常见的问题之一就是竞态条件(Race Condition)。竞态条件(Race Condition)是多线程或多进程并发执行时,由于而导致程序的依赖于执行序列的结果的情况。这意味着多个线程或进程在访问和修改共享数据时,如果没有适当的同步机制,可能导致意外的结果。竞态条件的经典示例是两个线程同时对共享变量进行读取-修改-写入操作。

Candy___i的博客 2285

Calibre电子书阅读器个性化样式定制指南

本文详细介绍了如何通过Calibre电子书阅读器的用户样式表功能进行深度个性化样式定制。从修改全局字体、行距、背景配色(包括深色/浅色模式)到美化代码块、引用等特殊元素,本指南提供了完整的CSS代码示例与实战技巧,帮助用户打造专属的舒适阅读环境,显著提升电子书阅读体验。

vv45678的博客 920

手把手教你用Cesium和RayMarching实现逼真体积云(附完整Shader代码)

本文详细介绍了如何利用Cesium和RayMarching技术实现逼真的体积云效果,包括环境准备、核心逻辑、云层建模和光照增强等关键步骤,并提供了完整的Shader代码。通过噪声函数选型、动态风场模拟和多重散射近似等技术,开发者可以在数字地球可视化项目中创建沉浸式天气效果,显著提升场景的真实感。

weixin_29230649的博客 415

CSP模型

CSP(Communicating Sequential Processes,通信顺序进程)是一种并发计算模型,用于描述并发系统中的各个进程之间通过通信进行协作的方式。CSP模型在并发编程领域有着广泛的应用,例如Go语言的并发模型就基于CSP模型设计。通过引入通道和协程(goroutine),Go语言提供了一种简单而强大的方式来编写并发程序,并且在语言级别上支持CSP模型的特性。CSP模型通过这种基于通信的方式,实现了进程之间的解耦和并发协作。这种方式避免了共享数据带来的并发访问问题,如竞态条件和死锁。

逐月 954

保姆级教程:用GMT6.1绘制专业地形起伏图(从数据下载到出图避坑)

本文提供了一份详细的GMT6.1绘制地形起伏图的保姆级教程,从环境搭建到数据下载,再到核心绘图命令解析,帮助用户避开常见错误。特别适合科研人员和地理信息爱好者快速掌握专业地形图的绘制技巧,提升工作效率。

weixin_42549723的博客 276

线程通信模型

和优先使用消息传递。

c39660570的博客 674

X86/64架构中的总线 和 ARM架构中总线的理解

内部总线 /CPU总线/FSB前端总线:类似ARM架构中的AHB总线北桥? 直接和CPU连接,这条总线主要由CPU使用,用来与高速缓存、主存和北桥(或MCH)之间传送信息。 外部总线:类似ARM架构中的APB总线(外围总线)南桥?例如PCI总线、USB总线等 通过北桥与CPU连接(南桥?),是CPU与内存RAM、ROM和输入/输出设备接口之间进行通讯的通路 内存总线:内存与北桥间的总线称为内存总线 ...

a746742897的博客 1067

#systemverilog# 之 event region 和 timeslot 仿真调度(三)Verdi 辅助查看

通过今天的学习,我们知道:event region 是event sequence 的全集。我们打开了 event region feature 也就开启了event sequence 的功能。

那么菜的博客 1365

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

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

qq_32702033的博客 3102

硬件测试有哪些?

硬件单元测试(UT)是验证电路功能与可靠性的关键环节,主要分为电源测试和信号测试两大模块。电源测试需验证输入电压范围、高低压极限、短路保护等功能,确保供电稳定性;信号测试则聚焦时钟、总线、存储等接口的时序与完整性。测试要求统一标准、可追溯数据、问题闭环处理,通过开发与测试协同确保质量。规范的单元测试能有效降低后期集成风险,提升产品可靠性,其核心始终是在最小单元上确保稳健性,为系统级可靠性奠定基础。

硬核科技 245

Go语言学习:浅谈数据通信并发模型Actor和CSP

Actor模型适合分布式系统和高并发应用,异步通信和容错性是其优势,但调试复杂。CSP模型适合并发编程和并行计算,同步通信和确定性使其易于理解,但在分布式系统中扩展性有限。选择哪种模型取决于具体应用场景和需求。

终极量化数据的专栏 1228

字符串尾部空格的迷思:深入解析 ABAP 隐式转换规则与 `strlen` 意外结果

看似简单的strlen之谜,背后实则是 ABAP 隐式转换的一整套严谨规则。只要开发者在赋值、输出、接口映射等关键节点建立“尾部空格意识”,辅以CONVCONDENSE等显式手段,就能有效杜绝多余空格引发的链式故障。希望本文的拆解与案例,能让你在面对下一个“异常长度”时,从容而笃定地给出正确答案。

2007 年 ~ 2025 年,深耕 SAP 技术 18 年 431

深入浅出讲解外部服务提供者 OAuth 2.0 帐户客户端创建与 ABAP 系统集成

本文详细介绍了在SAP ABAP平台配置OAuth 2.0客户端以安全调用外部Web服务的完整流程。主要内容包括:首先需要在外部服务提供者平台注册OAuth客户端,获取client ID和client secret;其次需特别注意重定向URI必须是公开可访问的地址;然后在ABAP系统中通过事务码OA2C_CONFIG配置OAuth客户端信息;最后阐述了常见的错误排查方法。文章强调了OAuth 2.0作为SAP系统与外部服务安全集成的标准协议,正确配置客户端是确保后续API调用安全可靠的关键前提。

2007 年 ~ 2025 年,深耕 SAP 技术 18 年 1734

并发模型值Actor和CSP

CSP的是(CSP)的缩写,翻译成中文是顺序通信进程,简称CSP的核心思想是多个线程之间通过Channel来通信,对应到golang中的chan结构,对应到Python中是QueueGo语言的CSP模型是由协程Goroutine与通道ChannelGo协程goroutine是一种轻量线程,它不是操作系统的线程,而是将一个操作系统线程分段使用,通过调度器实现协作式调度。是一种绿色线程,微线程,它与Coroutine协程也有区别,能够在发现堵塞后启动新的微线程。通道channel类似Unix的Pipe。....

go|Python的个人博客 433

PowerBuilder8.0

PowerBuilder8.0

关于Actor模型,CSP模型,Reactor模型,Proactor模型

1. Actor模型 传统的并发模型主要由两种实现的形式,一是同一个进程下,多个线程天然的共享内存,由程序对读写做同步控制(有锁或无锁). 二是多个进程通过进程间通讯或者内存映射实现数据的同步. Actors模型更多的使用消息机制来实现并发,目标是让开发者不再考虑线程这种东西,每个Actor最多同时只能进行一样工作,Actor内部可以有自己的变量和数据. 在Actors模型中,每个Actor都有一...

流的博客 2935

国外经典教材之液压控制系统(H.E梅里特)

电液伺服阀,液压控制系统开山之作,值得好好学习,细细品读。

毕业设计,私人牙科诊所管理系统,Java完整源代码,内含毕业论文的设计与实现、毕业答辩PPT、数据库脚本以及项目辅导视频

介绍牙科诊所管理系统为适应医疗信息管理发展的需要,开发基于B/S结构的私人牙科诊所病例管理系统。该系统应具有以下功能:(1)登陆模块,可分为管理员登陆和普通用户医生登录三个模块。(2)用户注册模块,对用户注册的用户名的要求,不同的用户要求要有不同的用户名。(3)系统管理模块,包括添加管理员,管理员密码的修改。(4)挂号管理模块,包括患者的名字、性别、年龄、现住地址和患者简介。(5)患者管理模块,对患者进行增加、患者删除、患者信息的修改。(6)开药管理模块,对药品的增加、删除、修改、查询,患者病历查(7)科室管理模块,管理员可以新建,修改,删除,科室信息(8)留言管理,管理员可以新建,修改,删除留言信息(9)预约挂号模块,用户可以在线进行预约挂号,用户可以选择普通号和专家号。

一步一步写线程之六数据通信并发模型Actor和CSP

数据通信模型和多线程编程本身是密不可分的,原则上来讲,谈及多线程编程一般就是要实现多线程之间的通信,否则多线程技术本身并没有什么可讨论的。一个技术其实如何能真得可以深入掌握进去,其实就是一个生态,围绕着它或近或远或紧密或间疏的有着各种各样的其它技术与之互相配合。挨过来一样,在其它的技术上,可能学习的这个技术又是其生态中的一环。明白了吧,你中有我,我中有你,这才最终形成了更广义上的计算机技术。

fpcc的专栏 954

cn-windows-7-ultimate-with-sp1-x64-dvd-u-677408.iso

cn_windows_7_ultimate_with_sp1_x64_dvd_u_677408.iso文件太大放百度云盘去了,失效请及时联系博主

【架构师之路】锁战争终结者:Actor与CSP如何颠覆传统并发编程?

每种并发模型都有其特定的优缺点和适用场景,选择合适的模型可以帮助开发者更有效地构建高并发、可靠的应用程序。根据具体的应用需求和上下文,开发者可以选择最匹配的并发计算模型。

代码时光 2182

并发编程(9)——Actor/CSP设计模式

简单来说,Actor在发送消息前必须知道接收方是谁,而接受方收到消息后也需知道发送方是谁,更像是邮件的通信模式。而csp是完全解耦合的,不关心消息从哪来或到哪去,只关心消息是通过哪个channel传递的。这里有一个问题需要注意:消费者线程是在生产者线程结束之后才运行的(消费者线程延迟500ms),那么就没有代码唤醒消费者线程,为什么消费者线程可以正常运行?主要步骤是通过条件变量挂起当前线程,若当前线程被唤醒,并且满足判断条件,则继续执行下面的代码,过程如下。如果不满足,线程继续挂起,等待被再次唤醒;

m0_63086198的博客 1758

Actor 还是 CSP?Go 中的并发模式还能讲这么细致

文章目录基本概念了解并发和并行CSP vs Actor 模型ActorCSP区别GO 中的并发模型并发设计模式Barrier 模式使用场景代码实现TipsFuture 模式使用场景代码实现Pipeline 模式使用场景代码实现Workers Pool 模式使用场景代码实现Pub/Sub 模式使用场景代码实现注意事项参考 基本概念 了解并发和并行 并发:强调一段时间做多件事 并行:强调同一时间做多件...

一个北漂的程序猿 1676

Awesome Go的并发模型:CSP模型与Actor模型比较

在现代分布式系统和高并发应用中,Go语言以其独特的并发模型脱颖而出。Go语言内置的CSP(Communicating Sequential Processes)模型与日益流行的Actor模型形成了两种截然不同的并发编程范式。本文将深入探讨这两种模型在Go生态系统中的实现、优劣对比以及适用场景。 > 读完本文,你将获得: > - CSP模型与Actor模型的核心概念理解 > - Go语言中两种模型...

gitblog_00956的博客 679

关于并发模型 Actor 和 CSP

最近在看《七天七并发模型》这本书,在书上介绍了 Actor 和 CSP 这两种并发模型。这两种模型很像,但还是有一些不同的地方。看完之后,比较困扰的是: 在什么场合使用哪种模型比较好呢? 在网上查了一些资料,在没有实现使用这两种模型进行编程的情况下,结合网上的资料,把自己的思考记录一下。下面先说说两种模型的不同点吧。一,主要的不同点1,关于消息发送方和接收方。 Actor:注重的处理单元,也就是

冲吧,不要停! 8884

并行编程模型之Actor/CSP/PGAS

并行编程模型之Actor/CSP/PGASActor1.背景2. 简介3.actor组成ActorMailbox邮箱behavior行为4.优势无锁异步隔离容错分布式5.劣势6.实践素数计算CSP1.简介2.CSP与go语言2.1 组成2.2Goroutine调度器3.Actor模型和CSP模型的区别PGAS1.简介2.实现 Actor 1.背景   处理并发问题就是如何保证共享数据的一致性和正确性,一般来说有两种策略用来在并发线程中进行通信:共享数据和消息传递。   熟悉c和java并发编程的都会比较熟悉

weixin_43728590的博客 2884

Actor模型和CSP模型的区别

Actor模型和CSP模型的区别   Akka/Erlang的actor模型与Go语言的协程Goroutine与通道Channel代表的CSP(Communicating Sequential Processes)模型有什么区别呢?   首先这两者都是并发模型的解决方案,我们看看Actor和Channel这两个方案的不同: Actor模型   在Actor模型中,主角是Actor...

diaoju3333的博客 112
上一篇: VSCode:Remote-SSH配置实录
下一篇: [Redis] Windows10搭建Redis集群
SixDayCoder
博客等级 码龄12年 98粉丝 64原创
评论 1
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值