由于工作上关系目前经常被各种并发数据问题搞得焦头烂额,要么要性能舍弃数据上得一致性,要么要一致性但是却得到了特别糟糕的响应。难道鱼和熊掌真的无法兼得吗?
然后找到了类似奥尔良这种基于Actor模型的kuangjia
首先本人因为是C#系的所以暂不考虑Java系那套,那摆在面前的此类型的框架其实就2个。 Akka.Net和Orleans。
什么是Actor?
Actor应该说是一种编程模型,一个Actor是一个最基本的计算单原,他能接收消息并执行计算(一个行为)
它最重要的特性是每个Actor之间互相隔离,互补共享内存,也就是说每个Actor都能维持一个私有状态且不能被别人所改变。
这对于我们意味着什么呢?想下一般我们遇到的并发问题,是不是在我们执行某个操作的时候,一个数据不正确的被另一个操作所干扰,导致数据最终混乱,而Actor则确保自己的数据不能被别人改变(独立维护自己的状态)以便使得最终一致。
wait
如果Actor自己数据不能被别人改变,那就是顺序执行?那会不会很慢?
对于一个Actor来说,没错,他还真的就顺序执行,因此能确保准确性
但是你真正系统里肯定不会只有一个Actor,而是由很多Actor组成,每个Actor之间是能并行的(因为他们不共享数据,所以他们可以互相独立的正确处理)
具体来说,当并行的消息到达一个Actor的时候,它会存储到一个MailBox(邮箱)里(你可以简单理解为一个队列),然后Actor从MailBox捞数据,一条一条顺序的捞
然后不同的Actor则并行着处理一样的事情
由于大家都是互相独立的处理各自的事情,数据不会发生冲突,也就无需类似锁之类的机制来确保数据一致性问题
由于Actor类文章网上搜索一大片, 在此就不再过多阐述了。
什么是奥尔良?
简单一句话,微软的一个基于Actor模型的实现,具体介绍可以更多参考官网
他跟正儿八经的Actor相比,微软习惯就是将其做更加上层的封装,Actor都变成了Grains,万事万物皆是Grains的感觉
我干了什么?
我也刚开始入门,发这篇文章主要是想证实下,Actor那套是不是真的那么神,本文涉及的所有代码均在 https://github.com/virtualcca/OrleansTest/tree/master 上面
既然他们说他们是以单线程来处理同一个Actor,那我就想测试下用Orleans搞一个并发转账的场景,和我常规的多线程并发转账场景的一个对比,而我想看到的结果是,常规版的由于多线程的问题数据总是错乱的,而奥尔良则能始终正确
转账代码
我有一个账户,账户上面有Money, 我能做2个操作,要么转钱过来,要么查看我还有多少钱,当然,转账总要点时间的对吧,所以转账时候Delay了1ms
实际转账的执行代码
可以注意下奥尔良版和原始版唯一区别在于
奥尔良版是通过client.GetGrain来获取了一个IAccount,这样获取到的是属于奥尔良托管的一个Client实例,对其执行的操作其实会发送到Host里执行,然后Host里就是正儿八经的Actor架构来去处理所有操作
但是正如之前介绍Actor的时候谈到单个Actor是单线程,而多个Actor之间是并发,如何确定你是一个还是多个Actor,是通过一个Id来区分(具体奥尔良官网有介绍),而GetGrain后面的那个0的参数就是他的Id,也就是我的这个IAccount是属于一个Actor
常规版直接new一个实例执行同样操作
然后代码运行,可以看到结果
原始版的结果仅供参考,我每次运行得出来的结果也都不一样(多线程执行顺序是不确定的)
而奥尔良版则能正确的恒定输出4950
至此,可以明确奥尔良完美的实现了Actor里关于单个Actor单线程的这么个处理。。。。