《通过C#学Proto.Actor模型》之PID
时间:2022-03-18 10:30
PID对象是代表Actor对象的进程,是能过Actor.Spawn(props)获取的;它有什么成员呢?既然代理Actor,首先有一个ID,标识自己是谁,Actor在Spawn时可以命名这个ID,否则会自动生成。还有三种向邮箱发消息的方法,Tell(),Request(),RequestAsync(),还有一个发送系统消息(Started,Stoping,Stoped等)方法SendSystemMessage(),还有一个停止的方法Stop()。
1 using Proto; 2 using System; 3 using System.Threading; 4 using System.Threading.Tasks; 5 6 namespace P004_PID 7 { 8 class Program 9 { 10 static void Main(string[] args) 11 { 12 var props = Actor.FromProducer(() => new MyActor()); 13 var pid = Actor.Spawn(props); 14 while (true) 15 { 16 Console.WriteLine("**************************************"); 17 Console.WriteLine("1、单向请求Tell 2、单向请求Request 3、双向请求RequestAsync"); 18 switch (Console.ReadLine()) 19 { 20 case "1": 21 Console.WriteLine("单向请求开始"); 22 pid.Tell(new Request { Name = "单向请求 Tell", RequestType = "one-way", Time = DateTime.Now }); 23 break; 24 case "2": 25 Console.WriteLine("单向请求开始"); 26 //无法接回应签,与官网说法不一 27 pid.Request(new Request { Name = "单向请求 Request", RequestType = "two-way-1", Time = DateTime.Now }, pid); 28 29 break; 30 case "3": 31 Console.WriteLine("双向请求开始"); 32 var response = pid.RequestAsync<Response>(new Request { Name = "双向请求 RequestAsync", RequestType = "two-way-2", Time = DateTime.Now }).Result; 33 Console.WriteLine(response.Time + ":" + response.Name); 34 break; 35 } 36 Thread.Sleep(2000); 37 } 38 } 39 } 40 41 public class MyActor : IActor 42 { 43 public Task ReceiveAsync(IContext context) 44 { 45 46 if (context.Message is Request request) 47 { 48 switch (request.RequestType) 49 { 50 case "one-way"://context.Sender为null 51 Console.WriteLine("接收到:" + request.RequestType + "," + request.Time + ":" + request.Name); 52 break; 53 case "two-way-1"://context.Sender= context.Self为自己 54 Console.WriteLine("接收到:" + request.RequestType + "," + request.Time + ":" + request.Name); 55 context.Respond(new Response() { Time = DateTime.Now, Name = "服务端应答 two-way-1" }); 56 break; 57 case "two-way-2"://context.Sender!= context.Self为新实例 58 Console.WriteLine("接收到:" + request.RequestType + "," + request.Time + ":" + request.Name); 59 context.Respond(new Response() { Time = DateTime.Now, Name = "服务端应答 two-way-2" }); 60 break; 61 } 62 } 63 return Actor.Done; 64 } 65 } 66 67 public class Request 68 { 69 public string Name 70 { get; set; } 71 public string RequestType 72 { get; set; } 73 public DateTime Time 74 { get; set; } 75 } 76 77 public class Response 78 { 79 public string Name 80 { get; set; } 81 public DateTime Time 82 { get; set; } 83 } 84 }
Actor中的Receive接到消息后,Context是中有两个PID对象,一个Self,一个Sender,Tell方法到达后,Sender对象为空;Request到达后,Sender=Self;而RequestAsync则Sender,Self都有对象,但不相同,这是一个区别。再有就是Tell和Request都是单向调用(我实测与官方文档说明有出入),RequestAsync是可以有返回值的,详见代码,如下是运行结果: