在第一篇Proto.Actor博文中,HelloWorld的第一行真正代碼是: var props = Actor.FromProducer(() => new HelloActor()); 這個返回的變數props就是一個Props的對象,它是負責創Actor實例,以及配置Actor實例,並... ...
在第一篇Proto.Actor博文中,HelloWorld的第一行真正代碼是:
var props = Actor.FromProducer(() => new HelloActor());
這個返回的變數props就是一個Props的對象,它是負責創Actor實例,以及配置Actor實例,並且產Actor上下文Context(類似asp.net中的Context)。
Props對象產生通常是用Actor.FromProducer或Actor.FromFunc產生,不過也可能實例化,實體例時可以給Actor做一系列配置,如下代碼:
1 using Proto; 2 using Proto.Mailbox; 3 using System; 4 using System.Threading.Tasks; 5 6 namespace P002_CustomProps 7 { 8 class Program 9 { 10 static void Main(string[] args) 11 { 12 var props = new Props() 13 //用道具代理返回一個IActor實例 14 .WithProducer(() => new MyActor()) 15 //預設調度器用線程池,郵箱中最多300個消息吞吐量 16 .WithDispatcher(new ThreadPoolDispatcher { Throughput = 300 }) 17 //預設郵箱使用無界隊列 18 .WithMailbox(() => UnboundedMailbox.Create()) 19 //預設策略在10秒的視窗內最多重新啟動子Actor 10次 20 .WithChildSupervisorStrategy(new OneForOneStrategy((who, reason) => 21 SupervisorDirective.Restart, 10, TimeSpan.FromSeconds(10))) 22 //可以將中間件鏈接起來以攔截傳入和傳出消息 23 //接收中間件在Actor接收消息之前被調用 24 //發送者中間件在消息發送到目標PID之前被調用 25 .WithReceiveMiddleware( 26 next => async c => 27 { 28 Console.WriteLine($"Receive中間件 1 開始,{c.Message.GetType()}:{c.Message}"); 29 await next(c); 30 Console.WriteLine($"Receive中間件 1 結束,{c.Message.GetType()}:{c.Message}"); 31 }, 32 next => async c => 33 { 34 Console.WriteLine($"Receive中間件 2 開始,{c.Message.GetType()}:{c.Message}"); 35 await next(c); 36 Console.WriteLine($"Receive中間件 2 結束,{c.Message.GetType()}:{c.Message}"); 37 }) 38 .WithSenderMiddleware( 39 next => async (c, target, envelope) => 40 { 41 Console.WriteLine($"Sender中間件 1 開始, {c.Message.GetType()}:{c.Message}"); 42 await next(c, target, envelope); 43 Console.WriteLine($"Sender中間件 1 結束,{c.Message.GetType()}:{c.Message}"); 44 }, 45 next => async (c, target, envelope) => 46 { 47 Console.WriteLine($"Sender中間件 2 開始,{c.Message.GetType()}:{c.Message}"); 48 await next(c, target, envelope); 49 Console.WriteLine($"Sender中間件 2 結束,{c.Message.GetType()}:{c.Message}"); 50 }) 51 // 預設的 spawner 構造 Actor, Context 和 Process 52 .WithSpawner(Props.DefaultSpawner); 53 54 //從props衍生pid,pid代理一個actor的地址 55 var pid = Actor.Spawn(props); 56 //把Hello對象交給HelloActor處理 57 pid.Tell(new MyEntity 58 { 59 Message = "我是MyEntity的Message,請求" 60 }); 61 Console.ReadLine(); 62 } 63 } 64 65 public class MyActor : IActor 66 { 67 public Task ReceiveAsync(IContext context) 68 { 69 if (context.Message is MyEntity myEntity) 70 { 71 Console.WriteLine(myEntity.Message); 72 context.Tell(context.Sender, new MyEntity() { Message = "我是MyEntity的Message,應答" }); 73 } 74 return Actor.Done; 75 } 76 } 77 public class MyEntity 78 { 79 public string Message { get; set; } 80 } 81 }
你會發現,Demo中,總有一個實例類+一個Actor類,這是構成Actor模型的必備,Actor類就是主體,實體類就是Actor類運算的載體,所以它們總是如影隨形。
第15 行到第21 行代碼含意以後會解釋。
這裡說Recevie和Sender的中間件,這裡很像一個AOP,可以在調用某個行為前後作處理統一的處理,比如日誌,許可權等統一的規則,也和asp.net core里的中件間如出一轍【如里你是一個asp.net core碼友,熟悉的Context,熟悉的next(),還有熟悉的Middleware】。
現在可以自己運行一下分析一下結果吧: