首页
学习
活动
专区
工具
TVP
发布
精选内容/技术社群/优惠产品,尽在小程序
立即前往

并行模型Actor

并行开发时经常需要关注加锁和原子操作等一系列线程问题,而Actor模型内部状态由它自己维护,内部数据只能自己修改,因此Actor不需要过多关注线程问题。

Actor模型

Actor由状态(State)、邮箱(Mailbox)和行为(Behavior)组成。

NewLife.Model.Actor设计为一个轻量级Actor模型,麻雀虽小五脏俱全!

/// 无锁并行编程模型

///

/// 独立线程轮询消息队列,简单设计避免影响默认线程池。

/// 适用于任务颗粒较大的场合,例如IO操作。

///

publicinterfaceIActor

{

/// 添加消息,驱动内部处理

/// 消息

/// 发送者

/// 返回待处理消息数

Int32Tell(Objectmessage,IActorsender=null);

}

IActor 接口设计为只有一个Tell方法,用于传递要发通知给目标Actor。这里的message可以列极为状态(State)。目标Actor内部有个队列收集信息,该队列可以认为是邮箱(Mailbox)。Actor内部有独立线程去读取 邮箱数据进行处理,即是行为(Behavior)!

从某种程度上来讲,Actor就是一个队列加上独立线程。如果该队列设计为分布式队列,那么这个Actor就成了真正的分布式并行模型。(如果Actor配上RedisQueue又会怎么样呢?)

Actor可以一个接着一个,串联起来,形成分布式并发处理集群。尽管是分布式系统,然而所有代码完全不需要考虑多线程问题。

总之,Actor模型的理念非常简单:万物皆Actor!

应用例程

我们来看一段测试代码,默认读取数据库然后生成Excel文件,两步都是比较耗时的操作。

[Fact]

publicasyncvoidTest1()

{

varsw=Stopwatch.StartNew();

varactor=newBuildExcelActor();

for(vari=;i

{

// 模拟查询数据,耗时500ms

XTrace.WriteLine("读取数据……");

awaitTask.Delay(500);

// 通知另一个处理器

actor.Tell($"数据行_");

}

// 等待最终完成

actor.Stop();

sw.Stop();

Assert.True(sw.ElapsedMilliseconds>6*500);

Assert.True(sw.ElapsedMilliseconds

}

privateclassBuildExcelActor:Actor

{

protectedoverrideasyncTaskReceiveAsync(ActorContextcontext)

{

XTrace.WriteLine("生成Excel数据:",context.Message);

awaitTask.Delay(500);

}

}

新建一个实现类继承Actor,重写ReceiveAsync,实现Actor行为(业务逻辑)。此时独占线程,所以无需考虑多线程问题。

跑起来看看日志输出

从上图可以看出,主逻辑和Actor是并行执行。主逻辑把数据送给Actor后,继续去读取下一页,无需等待Actor生成完成。

总结

XCode的实体延迟队列,就是一个货真价实的Actor模型。主逻辑只管处理业务,数据保存操作由另一个Actor完成。

DAL的数据导出、恢复和备份,也是Actor模型,主逻辑操作数据库,独立Actor负责写入文件,相比同一段逻辑完成该操作大概提升一倍性能。

  • 发表于:
  • 原文链接https://kuaibao.qq.com/s/20210118A0G26R00?refer=cp_1026
  • 腾讯「腾讯云开发者社区」是腾讯内容开放平台帐号(企鹅号)传播渠道之一,根据《腾讯内容开放平台服务协议》转载发布内容。
  • 如有侵权,请联系 cloudcommunity@tencent.com 删除。

扫码

添加站长 进交流群

领取专属 10元无门槛券

私享最新 技术干货

扫码加入开发者社群
领券