Dapr牵手.NET学习笔记:Actor小试
Actor模型是一種避免線程共享數(shù)據(jù),相同Actor實(shí)體串行化的方案,所以不便dapr的其他功能,幾乎都是非編程入侵的,相反,Dapr Acror深度定制的,關(guān)于Actor,.net中有一些通用框架,比如Akka.net,微軟的Orleans,還有最近復(fù)活的Proto actor。Dapr下的Actor,是dapr實(shí)現(xiàn)了一些庫(kù),基于這些庫(kù)來實(shí)現(xiàn)actor模型編程的。
本篇開個(gè)小頭,實(shí)際體會(huì)一下actor的作用,actor的一大作用就是實(shí)例隔離,相同實(shí)例不共享內(nèi)存,不同實(shí)例間還是可以并行的,當(dāng)然這個(gè)實(shí)現(xiàn)并不與OOP中的實(shí)例相等,還是看下面這個(gè)小例子吧,通過代碼來感覺。
一、首先定義一個(gè)類庫(kù)項(xiàng)目
需要引用Nuget包 Dapr.Actors
二、定義一個(gè)asp.net api項(xiàng)目
實(shí)現(xiàn)上面定義的接口,需要引入Nuget包Dapr.Actors.AspNetCore
需要在向Services中注入Actor
為了對(duì)比測(cè)試,可以定義一個(gè)/gettime的api,比較并串行
[ApiController] [Route("[controller]")] public class HomeController : ControllerBase {private readonly ILogger<HomeController> _logger;public HomeController(ILogger<HomeController> logger){_logger = logger;}[HttpGet("/gettime")]public IActionResult Get(string inTime){Task.Delay(3000).Wait();return Ok($"傳入時(shí)間:{inTime},返回時(shí)間:{DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff")}");} }三、添加一個(gè)Actor客戶端項(xiàng)目
需要引用Nuget包?Dapr.Actors
using?Dapr.Actors; using Dapr.Actors.Client; using IOrderFactoryActory.Interfaces;Console.WriteLine("回車開始"); Console.ReadLine();//調(diào)用api是并行的 var client = new HttpClient(); var httpTask1 = new Task(async () => {Console.WriteLine(await client.GetStringAsync("http://localhost:5000/gettime?intime=" + DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff"))); }); var httpTask2 = new Task(async () => {Console.WriteLine(await client.GetStringAsync("http://localhost:5000/gettime?intime=" + DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff"))); }); httpTask1.Start(); httpTask2.Start();//相同ID的actor是串行的,不同ID的actor是并行的 var factory = new ActorProxyFactory(new ActorProxyOptions { HttpEndpoint = "http://localhost:3999" }); var account1 = CreateActor(factory, "11111111111"); var account2 = CreateActor(factory, "22222222222"); var actorTask1_1 = new Task(async () => {Console.WriteLine(await account1.GetTimeAsync(DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff"))); }); var actorTask1_2 = new Task(async () => {Console.WriteLine(await account1.GetTimeAsync(DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff"))); }); var actorTask2 = new Task(async () => {Console.WriteLine(await account2.GetTimeAsync(DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff"))); }); actorTask1_1.Start(); actorTask1_2.Start(); actorTask2.Start();Console.WriteLine("回車結(jié)束"); Console.ReadLine();static IAccountActor CreateActor(ActorProxyFactory factory, string accountNo) {var actorType = "AccountActor";var actorId = new ActorId(accountNo); return factory.CreateActorProxy<IAccountActor>(actorId, actorType); }四、開始測(cè)試
啟動(dòng)sidecar
dapr?run?--app-id?account?--app-port?5000?--dapr-http-port?3999
運(yùn)行結(jié)果:
可以通過上面的例子看到,web api的傳入時(shí)間和返回時(shí)間幾乎相同,說明他們是并行運(yùn)行的,都在內(nèi)部等了3秒;Actor有兩個(gè)實(shí)例,是通過ActorID來區(qū)分實(shí)例的,ID為1開頭的兩個(gè)實(shí)例雖然傳入時(shí)間幾乎相同,但在返回時(shí)間上,第二次明顯是排在第一次返回后的(這正是Actor的串行基本準(zhǔn)則),ID為2開頭的,可以與1并行。
實(shí)際場(chǎng)景是什么呢?前一段時(shí)間開發(fā)了一套賬務(wù)系統(tǒng),場(chǎng)景是有很多賬戶批量入帳,當(dāng)然有可能有相同帳戶同時(shí)入帳,入帳時(shí)需要取出舊的帳戶余額,加上本次入帳金額,然后更新掉帳戶余額;因?yàn)槭峭ㄟ^web api調(diào)過來的并發(fā),處理辦法是在表的數(shù)據(jù)行上用行級(jí)鎖(DBA會(huì)罵娘的),保證兩個(gè)相同帳戶入帳時(shí),不會(huì)同時(shí)取,然后都用舊余額相加。但如果這里用Actor,就可以釋放數(shù)據(jù)庫(kù)的壓力(DBA會(huì)很開心的),相同帳戶的Actor是串行執(zhí)行,所以在業(yè)務(wù)層就避免了并發(fā),不同帳戶不受影響,關(guān)鍵是Actor是細(xì)小的顆粒,可以大量創(chuàng)建銷毀。篇幅和時(shí)間所限,下一篇會(huì)用例子來實(shí)現(xiàn)這個(gè)場(chǎng)景。
創(chuàng)作挑戰(zhàn)賽新人創(chuàng)作獎(jiǎng)勵(lì)來咯,堅(jiān)持創(chuàng)作打卡瓜分現(xiàn)金大獎(jiǎng)總結(jié)
以上是生活随笔為你收集整理的Dapr牵手.NET学习笔记:Actor小试的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: WPF中的命令(Command)
- 下一篇: 03Prism WPF 入门实战 - R