在演员模型中,演员有某种消息循环,其中使用例如消息来匹配消息。模式匹配(取决于语言ofc)
e.g。伪F#
let message_loop() =
let! message = receive_message() //sync receive message
match message with
| Foo(a,b) -> DoStuff(a,b)
| Bar(c) -> DoOtherStuff(c)
| _ -> error ("unknown message")
message_loop()
因此,消息签名与消息签名相匹配,并与要对消息内容执行的某些操作相关联。
这与调用实际方法之间有任何概念上的区别吗? 例如如果我在C#5中做以下事情:
class MyActor
{
//message signature Foo(a,b)
public void Foo(int a,string b)
{
Act( () => DoStuff(a,b) );
}
//message signature Bar(c)
public void Bar(int c)
{
Act( () => DoOtherStuff(c));
}
// the rest is infrasturcture code, can be refactored into an Actor Base class
//this emulates the sync behavior of the above actor
//each action is pushed onto a queue
//and then processed synchronously by the message handler
private void Act(Action action)
{
actions.Post(action);
}
private BufferBlock<Action> actions = new BufferBlock<Action>();
//this needs max degreee of parallellism = 1
private ActionBlock<Action> messageHandler = new ....
}
这样,在MyActor上调用方法将导致在消息队列上发布异步消息,该消息队列仅处理单种消息;一种行为。 但是,与消息关联的行为包含在消息本身中(从公共方法发布)
那么这是一个在C#5 / Async CTP中做演员的干净方式吗?
好处是消息被简单地定义为普通消息,而不是像类那样创建尴尬的消息DTO。
那么这足以让它发挥作用吗?
答案 0 :(得分:0)
基于任务的异步和MailboxProcessor之间存在细微差别。邮箱处理器将始终在同一个线程中,类似于Winforms消息循环。任务保持SynchronizationContext。这意味着Winforms和WPF的行为相同,但在使用线程池时,您最终可能会遇到不同的线程。
否则,从概念上讲,对我来说是正确的。
答案 1 :(得分:0)
我想说你的方法是合理的。
将F#代理封装在接口后面实际上是一种很好的做法,它本身会将消息分派给代理:
type IPrintText =
abstract Stop : unit -> unit
abstract Print : string -> unit
module Printer =
type private Message =
| PrintText of string
| Stop
let Start () =
let agent =
MailboxProcessor.Start (fun inbox ->
let rec loop () = async {
let! msg = inbox.Receive()
return!
match msg with
| PrintText text ->
printfn "%s" text
loop ()
| Stop -> async.Zero()
}
loop ())
{ new IPrintText with
member x.Stop () = agent.Post Stop
member x.Print text = agent.Post <| PrintText text }
let agent = Printer.Start ()
agent.Print "Test"
agent.Stop ()