当多线程并发遇到Actor

多线程并发总结六 Actor Model和Event Driven Actor Model也能有效的解决多线程的问题,跟CSP类似,他也是可以让变量由某一个Actor专门负责,而Actor是只会被一个线程执行的,所以也不会有多线程的问题。 Actor模型中的Actor类似CSP中的Process。CSP中的Process通讯相当于Actor中的信箱。 只是两者的定位并不一样,CSP主要用来解决某一个进程中的多线程问题,而Actor模型是一个分布式系统的逻辑架构... 阅读详情

1

多线程并发的难题

张大胖在做一个银行相关的项目,写了一个Account的类,用来表示一个用户的银行账号,根据银行的常规业务,自然要提供两个方法,存款(deposit)和取款(withdraw)。

为了防止多线程并发时导致的数据不一致问题,张大胖给每个方法都加了synchronized, 那意思很清楚,想进入某个方法执行存款或取款操作,必须得先获得一把锁才行。

0?wx_fmt=jpeg

(注:为了简化,这里没有做边界条件检查。)

但是在做转账操作的时候,为了保证一致性,必须得把两个账户都加上锁,然后才可以操作,于是张大胖写下了这样的代码,他觉得很简单,立刻就提交给Bill ,让他Review。

0?wx_fmt=jpeg

富有经验的Bill立刻就发现了问题,马上对张大胖说:“这样会出现死锁!”

张大胖说:“这么简单的代码,怎么可能有死锁?”

“假设线程1 做的操作是账户A给账户B转账, 先锁住了A账户, 接下来试图申请B账户的锁;

与此同时线程2 在从 账户B给账户A 转账, 先锁住了B账户的锁, 接下来试图申请A账户的锁。

两个线程各自持有资源, 然后等待获取对方的资源, 都无法执行下去, 死锁就出现了!”

张大胖无言以对,不得不承认Bill是正确的。他问道:“那怎么解决这个问题?”

“非常简单,加锁的时候按次序来就可以了,例如所有的线程,无论是从A向B转账,还是从B向A转账,都先获得账号A的锁,成功后再获得账户B的锁,这样就没问题了。”

张大胖说:“那样代码会变得很古怪啊,还得给两个账户排个顺序,如果不知道背后的思想读起来很痛苦,怪不得人家说多线程编程很难啊。”

Bill说:“是啊, 其实线程这个东西,就是一段代码的执行而已, 是操作系统层面的概念,可是我们苦逼的程序员不得不来面对它,来背这个多线程并发的锅了。”

2

黑盒子

下班后,张大胖一直在思考这个问题:既然线程是操作系统层面的概念,能不能把线程的概念隐藏起来,然后所有的操作都不用加锁呢? 这样以来编程就会容易得多啊!

本质的问题是什么?

首先是共享的状态,例如Account中的balance ,多个线程都要读写, 其次就是多个线程乱序、并发执行。

能不能换个思路,把这个Account对象看成一个黑盒子,你想存款了,就发一个存款的消息过来,想取款就发一个取款的消息过来。

不管是有一个消息,还是有100个消息,我统统放到黑盒子的一个队例中,然后让Account对象一个个顺序处理不就可以了? 根本不用在方法上加锁!

这样做,其实就是把并发的操作变成了串行的操作而已!

0?wx_fmt=png

不对,如果调用方把取款消息放下就走, 不等待返回结果, 那就不是同步操作,而是异步操作了!

但是如果取款的时候发现余额不足,怎么通知调用方?嗯,调用方也必须是个黑盒子对象,也向它发送异步消息,这个消息也会在消息队列中存下来,调用方“黑盒子”也会一个个处理。

0?wx_fmt=png

想到这一层,张大胖激动起来:取款和存款的操作就不用在加锁了,码农们只要考虑黑盒子对消息的处理即可:取出消息,处理消息,向别的黑盒子发送消息,  根本不用考虑线程这样底层的概念了。

3

Actor模型

第二天张大胖赶紧找到Bill, 向他炫耀自己的“新发明”。

Bill不动声色:“小伙子,不错啊,重新发明了轮子!”

“重新发明?”

“是啊,你这个所谓黑盒子,就是所谓Actor模型啊! 它最早由Carl Hewitt在1973定义,其消息传递的方式更加符合面向对象的原始意图, 这一点我想你也体会到了,要不你怎么把他们叫做黑盒子啊。”

“1973年? 我还没出生。唉,看来这些概念已经被老前辈们都发明完了啊。”

“Actor属于并发组件模型 ,可以把程序员从多线程并发或线程池等基础概念中解放出来。它有这么几个特点:”

Actor:

就是你说的黑盒子,系统是由很多Actor组成。 Actor之间不共享状态,但是会接收别的Actor发送的异步消息,处理的过程中,会改变内部状态,也可能向别的Actor发送消息。

Message:

消息是不可变的, 它的发送都是异步的,Actor内部有个“MailBox”来缓存消息。

MailBox:

Actor内部缓存消息的邮箱, 其他Actor发送的消息都放到这里,然后被本Actor处理,类似有多个生成者和一个消费者的队例。

0?wx_fmt=png

张大胖说:“和我之前的图差不多,看来我确实是重新发明了轮子啊。”

4

用Actor实现转账

Bill 笑道:“这个Actor看起来很美,但是编程的时候你得刷新一下你的思维才行。 大胖,之前你的转账操作在多线程下不是会出现死锁吗? 你考虑下,如果用Actor的思路该怎么写?”

“首先,得有两个Actor, 这两个Actor 表示了两个账户,我把它们叫做旺财和小强。”

“然后呢,转账的逻辑怎么处理?”

张大胖想了一会:“既然转账是在两个Actor之间发生的,那可以引入一个协调者Actor,叫做转账管家吧。不过,由于消息都是异步的,转账管家向旺财这个Actor发起扣款请求以后,不知道什么时候才能真正执行扣款,也不能立刻知道是否成功,必须得等待啊,这就有点麻烦了。”

Bill说:“我给你画个流程图,你看看。”

0?wx_fmt=png

张大胖感慨地说:“原来的多线程并发模型,需要同时锁住两个账户,然后才能进行转账。现在每个Actor都独立,也把这个转账给搞定了。”

Bill说:“其实对于转账管家来说,对每个转账的消息,内部是隐含一个流程状态的,就是先向某个账户扣款,成功以后再向另一个账户增加,最后给调用者返回状态,这个次序是不能乱的。看到图中那个Transaction ID没有(Tx01),就是用来跟踪这个转账的事务。”

4

漏洞

“我发现了一个漏洞,你这个转账虽然看起来很美,没有加锁,但是和原来的是有区别的,原来多线程思路是会把旺财和小强的账户同时锁住,然后转账,在这个过程中,别人是不能操作这两个账号的! 而你的Actor方案中,当转账管家给旺财发消息扣款的时候,小强其实是自由的,如果这时候小强的账户被冻结,那你的转账管家还得回滚旺财的扣款,这多麻烦啊。”

Bill:“哈哈,你小子还挺机灵的嘛,看出了这个问题,Actor模型非常适用于多个组件独立工作,相互之间仅仅依靠消息传递的情况。如果想在多个组件之间维持一致的状态(比如咱们例子中的转账),那就不爽了。”

“那怎么解决这个问题?”

“那必须得用一些特殊手段了,有些实现Actor的框架,例如Akka,专门提供了像Coordinated /Transactor这样的机制来处理这个问题。有空的话给你仔细讲讲。”

“好吧,我回头看看这个Akka, 对了, Actor虽然对用户隐藏了线程, 但是总得有线程来处理消息吧。” 张大胖问道。

“那是肯定的,线程本质上就是一段代码的执行,每个Actor在处理消息的时候,肯定得和线程关联才行,只不过Actor系统把线程这个概念给隐藏了。”

“有哪些系统实现了Actor?” 张大胖接着问。

“其实最著名的就是Erlang了,Actor模型可以说是它的基础,除了我们上面所说的,还可以让Actor之间建立关联,例如让一个Actor去监控另外一些Actor工作,如果那些Actor崩溃了,就新建一个Actor继续工作。在Java 领域,刚才提到的Akka是比较知名的一个Actor框架。 ”

(完)

你看到的只是冰山一角, 更多精彩文章,请移步《2016文章精华》或者《2017文章精华》


码农翻身

用故事讲述技术

0.jpeg

【消息队列】——如何使用Actor模型解决并发问题 摘要 本文探讨了Actor模型在多线程并发编程中的优势与应用。文章首先分析了传统共享内存模型面临的挑战,包括线程安全、竞争条件以及同步机制带来的死锁等问题。随后详细介绍了Actor模型的核心思想:每个Actor独立维护状态和消息队列,通过消息传递实现通信,从而避免共享内存带来的并发问题。通过餐厅点餐的生动案例,展示了Actor模型如何简化并发程序设计。文章还讨论了Actor模型的优势(简单可靠、高性能、易扩展)和局限性(设计复杂度高、高并发场景限制、分布式事务处理困难),并比较了不同语言对Actor模型的支 阅读详情

相关推荐

HarmonyOS 开发——并发模型对比(Actor与内存共享)

Actor并发模型中,每一个线程都是一个独立Actor,每个Actor有自己独立的内存,Actor之间通过消息传递机制触发对方Actor的行为,不同Actor之间不能直接访问对方的内存空间。Actor并发模型对比内存共享并发模型的优势在于不同线程间内存隔离,不会产生不同线程竞争同一内存资源的问题。目前ArkTs提供的多线程并发能力都基于Actor并发模型在介绍TaskPool和Worker前,我们先了解下多线程并发中的两个并发模型:Actor并发模型、内存共享并发模型。

duoduola666的博客 1100

使用Actor模型管理Web Worker多线程

前端固有的编程思维是单线程,比如JavaScript语言的单线程、浏览器JS线程与UI线程互斥等等,Web Woker是HTML5新增的能力,为前端带来多线程能力。这篇文章简单记录一下搜狗地图WebGL引擎(下文简称WebGL引擎)使用Web Worker的一些实践方案,虽然这个项目最终夭折并且我也从搜狗离职了,但在开发WebGL引擎过程中的一些心得和实践还是值得写一写的。 搜狗地图WebGL引擎使用Actor模型管理worker线程,所以这篇文章就围绕这一点展开,包括以下内容: WebGL引擎为何

嘿嘿 547

Anolis龙蜥内核升级实战:从查询到配置的全流程指南

本文提供了一份详尽的Anolis龙蜥操作系统内核升级实战指南。文章从升级的必要性出发,逐步讲解了升级前的系统检查与备份、从官方源获取正确内核包、分步安装与验证、配置默认启动项以及升级后的功能验证与安全回滚方案。旨在帮助运维人员安全、平稳地完成内核升级,以获取性能提升、新硬件支持及重要的安全漏洞修复。

qq_27496129的博客 572

Scala Actor并发编程模型

Scala Actor并发编程模型 1. Actor介绍 Scala中的Actor并发编程模型可以用来开发比Java线程效率更高的并发程序。我们学习Scala Actor的目的主要是为后续学习Akka做准备。 1.1 Java并发编程的问题 在Java并发编程中,每个对象都有一个逻辑监视器(monitor),可以用来控制对象的多线程访问。我们添加sychronized关键字来标记,需要进行同步加锁访问。这样,通过加锁的机制来确保同一时间只有一个线程访问共享数据。但这种方式存在资源争夺、以及死锁问题,程序越

qq_36382679的博客 870

基于C#的ASP.NET开发的党史学习网站课设

开展党史学习教育,就是要以史为镜、以史明志,把苦难辉煌的过去、日新月异的现在、光明宏大的未来贯通起来,在鉴往知来中砥砺前行,在乱云飞渡中把准航向,在凝心聚力中团结奋斗,共同创造新的历史伟业。登陆按钮与数据库进行连接,逻辑实现是如图3.1.3所示,自己定义一个SQL查询语句,将账号、密码放入SQL查询语句中,用sqlDataReader.HasRows语句进行逐一比较,找出结果,将用户名存入session并调用cookies,如果结果存在就关闭数据库,进行数据跳转,并弹出登陆成功的提示框,并关闭数据库。

m0_62408555的博客 974

c语言面试5(希诺麦田)

在 C 语言中,当使用strlen函数计算字符串的长度时,它会返回字符串中字符的实际个数,不包括字符串结束符’\0’。而sizeof(array)返回的是array指针所占用的字节数,通常在 32 位系统上为 4 个字节,在 64 位系统上为 8 个字节。在给定的代码中,array被初始化为"\0\0",其中包含两个转义字符’\0’。当使用strlen函数计算array的长度时,它会遇到第一个’\0’并停止计数,因此返回的长度为 2。12.下面四个选项是四个整数在内存中的存储情况,其中数值最大的一个是。

Pierce110110的博客 1053

多核编程4种方式:多线程、多进程、csp(轻量级线程)、actor(轻量级进程)

1)多线程方式利用多核心 锁(信号量、互斥锁、自旋锁、读写锁、原子锁cas、乐观锁、悲观锁) 锁的粒度 什么情况下用什么锁,比较困惑 消息队列 管道(不需要加锁): pipe+epoll/select/epoll 资源+锁 并发实体:线程 总结: 需要大量的锁。 2)多进程方式利用多核心 共享内存 pipe管道、 父进程fork子进程有限制 只能一端读...

focus-unchanged-thing 1593

海康威视4G摄像头直连实战:不用萤石云,手把手教你用ISUP SDK搞定跨网段视频流

本文详细介绍了如何通过海康威视ISUP SDK实现4G摄像头的直连通信,提供了一套零平台费、自主可控的技术方案。文章涵盖技术选型、设备端配置、服务器端开发及高级应用场景,特别适合中小型安防项目,帮助开发者解决跨网段视频流传输难题,降低长期运营成本。

weixin_27076351的博客 470

多进程-> 多线程 -> 异步 -> EventDriven -> Actor模式

聊聊计算机界的家常

weixin_41308834的博客 1834

【毫米波混合波束成形】第3章 深度展开网络:将迭代优化嵌入计算图

相位提取算子 $P_\phi: \mathbb{C}^N \to \mathbb{C}^N$ 定义为逐元素相位归一化 $P_\phi(z) = \exp(j \cdot \angle z)$。该算子在复数域非全纯(Non-holomorphic),标准反向传播需扩展至Wirtinger微积分框架。对于复数变量 $z = x + jy$,Wirtinger导数定义:相位提取算子的Jacobian矩阵在极坐标下具有稀疏结构。

VectorShift的博客 407

几款开源的自动驾驶仿真平台项目

它被开发为一个虚幻的插件,可以简单地放到任何你想要的虚幻环境中。第一类是基于合成的数据,对环境、感知及车辆进行模拟,这里的感知大多数是图像层面的感知,这类模拟器主要用于感知、规划算法的初步开发上,Carla、AirSim、Udacity self-driving car simulator就属于这类;第二类是基于真实数据的回放,这里的真实数据包括图像、lidar、radar等各种传感器的数据,这类模拟器主要用于测试无人驾驶中信息融合算法以及车辆不同部件的性能,Apollo和Autoware就属于这类。

南七小僧的学海无涯 2850

使用Actor模型对词频统计程序进行多线程优化

词频统计程序是一个相当简单的程序:它读一个文件夹里的所有指定类型的文件,统计其中出现的英文单词的次数,并排序输出。 但是它却有很大的优化余地,甚至可以分布式到多台机器中(Map-Reduce模型)。但是,在单机中搞这么复杂反而会增加运行时间和内存。 我们希望将它改造成多线程。但是,分词过程和统计过程若分布到多个线程中,则对内存的锁会增加,因为大部分算法的时间效率都是O(n)的,而且对内存的操作...

weixin_30407099的博客 209

STM32入门教程:智能马桶盖控制

通过编写相应的代码,您可以根据需要实现其他功能,例如座圈温度调节和液晶显示屏显示等。初始化配置 首先,使用STM32CubeMX创建一个新的工程,并选择您所使用的STM32单片机型号。智能马桶盖是一种集成了多种功能的智能家居设备,通过控制芯片来实现自动冲水、座圈加热、座圈温度调节等功能。在本教程中,我们将使用STM32系列单片机来控制智能马桶盖的各个功能。以上代码演示了如何通过STM32的GPIO控制引脚来控制智能马桶盖的冲水和座圈加热功能。写代码 接下来,我们将通过编写代码来控制智能马桶盖的各个功能。

2401_85258012的博客 657

从java的多线程到erlang的actor并发模型

多线程并发的难题 张大胖在做一个银行相关的项目,写了一个Account的类,用来表示一个用户的银行账号,根据银行的常规业务,自然要提供两个方法,存款(deposit)和取款(withdraw)。 为了防止多线程并发时导致的数据不一致问题,张大胖给每个方法都加了synchronized, 那意思很清楚,想进入某个方法执行存款或取款操作,必须得先获得一把锁才行。 (注:为了简化,这里没有做边界条件检查。) 但是在做转账操作的时候,为了保证一致性,必须得把两个账户都加上锁,然后才可以操作,于是张大胖写下了这样的代

qq_35218302的博客 560

python利用IQR方法与3σ方法进行异常值处理(含代码)

python利用IQR方法进行异常值处理

weixin_46713695的博客 2031

OV9734 DATASHEET,完整规格书

OV9734完整规格书,包括电气参数,尺寸规格,寄存器配置表等

鸿蒙多线程开发——并发模型对比(Actor与内存共享)

并发是指在同一时间段内,能够处理多个任务的能力。为了提升应用的响应速度与帧率,以及防止耗时任务对主线程的干扰,HarmonyOS系统提供了异步并发和多线程并发两种处理策略。指异步代码在执行到一定程度后会被暂停,以便在未来某个时间点继续执行,这种情况下,同一时间只有一段代码在执行。它允许在同一时间段内同时执行多段代码。在主线程继续响应用户操作和更新UI的同时,后台也能执行耗时操作,从而避免应用出现卡顿。并发能力在多种场景中都有应用,其中包括单次I/O任务、CPU密集型任务、I/O密集型任务和同步任务等。

harmonyClassRoom的博客 1297

蓝牙模块HM-10手册

蓝牙模块HM-10手册,该手册对蓝牙模块HM-10进行了详细的介绍和使用方法以及一些AT指令。

Python 并发编程终极对比:多线程、多进程、协程和 Actor 模型的取舍矩阵

Python 并发编程的选择太多了:threading、multiprocessing、asyncio、concurrent.futures,还有第三方库 gevent、uvloop、Pykka。每种方案都有自己的拥趸,但很少有人能把它们的适用场景、性能特征和坑点一次性讲清楚。我在公司内部做过一次"并发方案选型"的分享,把四种主流方案做了一个取舍矩阵。这篇就是这个矩阵的文字版,希望能帮你少走弯路。

2401_87746054的博客 6659

复分析 阿尔福斯(Ahlfors) 第三版答案 英文

答案分为十章,有部分习题没有答案,全英文复分析阿尔福斯(Ahlfors) 第三版答案

lwip-2.0.3

lwip是瑞典计算机科学院(SICS)的Adam Dunkels 开发的一个小型开源的TCP/IP协议栈。实现的重点是在保持TCP协议主要功能的基础上减少对RAM 的占用。

scala——Actor模型、并发编程、多线程统计单词案例、java并发抹胸缺点、actor如何优化

Scala中的Actor并发编程模型可以用来开发比Java线程效率更高的并发程序

qq_40585384的博客 1463

Atitit 并发处理 go与 java对比较 目录 1. 并发编程的七个模型 线程,fp,actor,csp 数据级并行 Lambda 1 2. 四种并发编程模型简介 多线程,callback

Atitit 并发处理 go与 java对比较 目录 1. 并发编程的七个模型线程,fp,actor,csp 数据级并行Lambda 1 2. 四种并发编程模型简介多线程,callback Actorcsp 2 3. JVM上的Thread, Thread Pool, Future, Rx, async-await, Fiber, Actor等并发编程模型 5 3.1. Actor与分布式架构 5 4. 5种常见的并发模型Future模型Fork/Join模型3、Ac...

attilax的专栏 347

多线程并发模型:Actor模型在ArkTS中的应用(172)

在 ArkTS 中,多线程并发编程彻底摒弃了传统基于“共享内存”的模型,全面采用了基于消息传递的。这种设计从底层架构上避免了复杂的锁竞争与数据竞争问题。

Davina_yu的博客 151

scala多线程之actor并发编程模型

首先描述一下线程的状态。 线程的状态转换是线程控制的基础。线程状态总的可分为五大状态:分别是生、死、可运行、运行、等待/阻塞;新状态:线程对象已经创建,还没有在其上调用start()方法。2、可运行状态:当线程有资格运行,但调度程序还没有把它选定为运行线程时线程所处的状态。当start()方法调用时,线程首先进入可运行状态。在线程运行之后或者从阻塞、等待或睡眠状态回来后,也...

weixin_33873846的博客 210

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

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

Candy___i的博客 2285

HarmonyOS:多线程并发

当前ArkTS提供了TaskPool和Worker两种并发能力,TaskPool和Worker都基于Actor并发模型实现。

ChinaDragon10的博客 1145
上一篇: 黑客三兄弟(续)
下一篇: 算法分析神器—时间复杂度
码农翻身
码农翻身 《码农翻身》作者 《码农翻身》作者
博客等级 码龄8年 3万+粉丝 1084原创
评论 1
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值