2011-04-25 4 views
4

액터 모델에서 액터는 메시지 정렬과 같은 메시지 루프를 가지고 있습니다. 패턴 일치 (ofc 언어에 따라 다름)C# 5/Async CTP에서 액터 모델 구현

의사 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의 메소드를 호출; 행동. 그러나 메시지와 관련된 동작은 메시지 자체에 포함되어 있습니다 (public 메서드에서 게시 됨)

C# 5/Async CTP에서 배우를 수행하는 데는 깨끗한 방법으로 간주됩니까?

메시지가 단순히 클래스처럼 어색한 메시지 DTO를 만드는 대신 일반 메시지로 정의된다는 이점이 있습니다.

이렇게하면 충분합니까?

+2

이 스타일은 코드 검토에서 가정에서 더 느낀다. 그것은 나의 취향을 위해 약간 개방적이다. http://codereview.stackexchange.com/ – GregC

+0

아마도 새로운 [async/await를 사용하는 C#의 Agent/MailboxProcessor] (http://stackoverflow.com/questions/4075189/agent-mailboxprocessor-in-c-sharp-using- new-async-await) – Benjol

+1

C#을 사용하는 경우 Rx를 대신 학습하는 것이 좋습니다. 그것은 매우 강력하고 효율적이며 표현력이 뛰어납니다. Rx로 문제를 모델링 할 수 있어야합니다. 에이전트 지향 접근 방식보다 F #에 Rx를 추천하기도합니다. 또한 C#으로 구현할 때 버그가 될 수있는 많은 코너 케이스가 Rx 팀에서 다룰 예정입니다. –

답변

0

작업 기반 비동기와 MailboxProcessor간에 약간의 차이가 있습니다. 사서함 프로세서는 Winforms 메시지 루프와 마찬가지로 항상 같은 스레드에서 종료됩니다. 작업은 SynchronizationContext를 유지합니다. 이것은 Winforms 및 WPF에 대해 동일한 동작을 의미하지만 스레드 풀을 사용하여 작업 할 때 다른 스레드로 끝날 수 있습니다.

그렇지 않으면 개념적으로 나에게 잘 보인다.

+1

MailboxProcessor는 내부적으로 RegisterWaitForSingleObject를 사용하여 스레드 풀에 게시하지만 스레드가 매 300 반복을 건너 뛰게하는 내부 트램 폴린에 의해 뒷받침됩니다. MailBox 프로세서 내의 비동기는 Async.SwitchToContext를 사용하여 특정 스레드를 강요 할 수 있습니다. – 7sharp9

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()