Actor模型是一种避免线程共享数据,相同Actor实体串行化的方案,所以不便dapr的其他功能,几乎都是非编程入侵的,相反,Dapr Acror深度定制的,关于Actor,.net中有一些通用框架,比如Akka.net,微软的Orleans,还有最近复活的Proto actor。Dapr下的Actor,是dapr实现了一些库,基于这些库来实现actor模型编程的。

本篇开个小头,实际体会一下actor的作用,actor的一大作用就是实例隔离,相同实例不共享内存,不同实例间还是可以并行的,当然这个实现并不与OOP中的实例相等,还是看下面这个小例子吧,通过代码来感觉。

一、首先定义一个类库项目

需要引用Nuget包 Dapr.Actors

public interface IAccountActor : IActor
{Task<string> GetTimeAsync(string inTime);
}

二、定义一个asp.net api项目

实现上面定义的接口,需要引入Nuget包Dapr.Actors.AspNetCore

public class AccountActor: Actor, IAccountActor{      public AccountActor(ActorHost host) : base(host){           }public async Task<string> GetTimeAsync(string inTime){Console.WriteLine($"{this.Id}开始");Task.Delay(3000).Wait();Console.WriteLine($"{this.Id}结束");return await  Task.FromResult($"Actor ID:{this.Id} 传入时间:{inTime},返回时间:{DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff")}");}}

需要在向Services中注入Actor

using OrderFactoryService;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;var builder = WebApplication.CreateBuilder(args);
builder.Services.AddControllers();
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();
//注入Actor
builder.Services.AddActors(options =>
{options.HttpEndpoint = "http://localhost:3999";    options.Actors.RegisterActor<AccountActor>();
});var app = builder.Build();if (app.Environment.IsDevelopment())
{app.UseSwagger();app.UseSwaggerUI();
}
app.UseAuthorization();app.UseRouting();
app.UseEndpoints(endpoints =>
{   //Map Actor Handlerendpoints.MapActorsHandlers();
});
app.MapControllers();
app.Run();

为了对比测试,可以定义一个/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($"传入时间:{inTime},返回时间:{DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff")}");}
}

三、添加一个Actor客户端项目

需要引用Nuget包 Dapr.Actors

using Dapr.Actors;
using Dapr.Actors.Client;
using IOrderFactoryActory.Interfaces;Console.WriteLine("回车开始");
Console.ReadLine();//调用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("回车结束");
Console.ReadLine();static IAccountActor CreateActor(ActorProxyFactory factory, string accountNo)
{var actorType = "AccountActor";var actorId = new ActorId(accountNo);   return factory.CreateActorProxy<IAccountActor>(actorId, actorType);
}

四、开始测试

启动sidecar

dapr run --app-id account --app-port 5000 --dapr-http-port 3999

运行结果:

可以通过上面的例子看到,web api的传入时间和返回时间几乎相同,说明他们是并行运行的,都在内部等了3秒;Actor有两个实例,是通过ActorID来区分实例的,ID为1开头的两个实例虽然传入时间几乎相同,但在返回时间上,第二次明显是排在第一次返回后的(这正是Actor的串行基本准则),ID为2开头的,可以与1并行。

实际场景是什么呢?前一段时间开发了一套账务系统,场景是有很多账户批量入帐,当然有可能有相同帐户同时入帐,入帐时需要取出旧的帐户余额,加上本次入帐金额,然后更新掉帐户余额;因为是通过web api调过来的并发,处理办法是在表的数据行上用行级锁(DBA会骂娘的),保证两个相同帐户入帐时,不会同时取,然后都用旧余额相加。但如果这里用Actor,就可以释放数据库的压力(DBA会很开心的),相同帐户的Actor是串行执行,所以在业务层就避免了并发,不同帐户不受影响,关键是Actor是细小的颗粒,可以大量创建销毁。篇幅和时间所限,下一篇会用例子来实现这个场景。

Dapr牵手.NET学习笔记:Actor小试相关推荐

  1. Dapr牵手.NET学习笔记:状态管理之docker-compose发布

    Dapr牵手.NET学习笔记:想入非非的服务调用 Dapr牵手.NET学习笔记:跨物理机负载均衡服务调用 Dapr牵手.NET学习笔记:用docker-compose部署服务 说明:为了给出demo的 ...

  2. Dapr牵手.NET学习笔记:开篇

    dapr,一个为分布式应用程序的运行时,为开发者在对接分布式组件时,提供了便利.使用dapr带来的好处可扩展性,因为它是通过sidecar的理概念来集成其他运行时的.同时dapr还提供了多种语言的SD ...

  3. Dapr牵手.NET学习笔记:Actor一个场景

    接上一篇最后的场景,为了解决相同帐户并发引起的数据库行级锁,可以引入Actor的串机制,相同ActorID的实例,串行,这样就能在应用层把读取余额的资源争抢解决掉,剩下的工作就是一定时间间隔,把内存中 ...

  4. Dapr牵手.NET学习笔记:可观测性-分布式跟踪

    分布式跟踪在dapr里是开箱即用的,不需要对应用作任何一丁点的侵入式编程.之前的开发,如果想实现分式跟踪,就得在应用中埋点,这是一个与业务无关系的动作.dpar通过sidecar可以轻松做到这点,从而 ...

  5. Dapr牵手.NET学习笔记:绑定

    绑定有点像订阅发布,但又不一样,绑定更简单,绑定输出(调用方)-绑定输入(被调用方). 本例是用docker compose编排,并且用rabbitMQ来支持,因为rabbitMQ支持输入和输出绑定. ...

  6. Dapr牵手.NET学习笔记:发布-订阅

    queue,是很好的削峰填谷工具,在业内也是主流:发布订阅,可以有效的解耦两个应用,所以dapr把他们进行了有效的封装,我们使用起来更简单高效. 本篇的案例是下完订单后,会把消息发布到redis(当然 ...

  7. Dapr牵手.NET学习笔记:状态管理进阶(二)

    为了防止并发对数据修改造成差异,dapr使用了etag标签来作为版本号,对数据修改进行验证. 下面是对etag的一个demo appsettings.json中的url配置 "StateUr ...

  8. Dapr牵手.NET学习笔记:状态管理进阶(一)

    在上一篇文章中说到,dapr默认的状态是不可能跨appid的,也就是只能在相同的应用内访问自己设置的状态数据,dapr支持三种状态的共享配置:appid,nam,none,是通过修改component ...

  9. Dapr牵手.NET学习笔记:用docker-compose部署服务

    上一篇聊到用两个物理机(一个win,一个mac)来部署dapr和服务 ,实现order调用pay的负载均衡.本篇说一下在windows上的docker部署这三个服务,达到与上一篇的效果. 三个服务的部 ...

最新文章

  1. 修改wamp默认网站目录
  2. 多选取值_R语言缺失值的处理——回归预测法
  3. Fiddler抓包使用教程-扫盲篇
  4. php session存到redis,php Session存储到Redis的方法
  5. uboot中关于LCD的代码分析
  6. 转债---Pregel: A System for Large-Scale Graph Processing(译)
  7. c/c++ 中文件路径的表示
  8. 在el-table中使用el-popover,没法点击确定或取消来关闭添加 多个按钮
  9. .NET: 如何在宿主中动态加载所有的服务
  10. head first JavaScript pdf 下载
  11. ArduinoUNO实战-第十八章-三基色LED实现七彩色渐变
  12. 新手如果写一个软件,应该是怎么一个流程?
  13. fatal error C1083:/fatal error C1010: 错误处理
  14. 五、Ceph之RBD存储使用
  15. 北理工2013《Java程序设计》课程设计要求
  16. PaaS平台设计思想
  17. 基于Python的动漫人物分类识别系统
  18. 跑步用app轨迹画得比较准确的居然是“咕咚”
  19. 《C++ Primer》第9章 9.3节习题答案
  20. 破解webshell方法~

热门文章

  1. poj 1986 Distance Queries
  2. SQL server 2000 和2005中怎么让ldf文档变小
  3. UITabBar Contoller
  4. Android 电量优化
  5. 安装mongoDB遇见的一个路径问题
  6. 旺财速啃H5框架之Bootstrap(五)
  7. iOS方法类:CGAffineTransform
  8. Java设计模式----策略模式(Strategy)
  9. sql查询结果集根据指定条件排序的方法
  10. Oracle数据库案例整理-Oracle系统执行时故障-Shared Pool内存不足导致数据库响应缓慢...