2010-11-02 73 views
7

這個問題結合了兩個主題,我不完全理解代理/ MailboxProcessor在C#中使用新的異步/等待

通過paper約異步F#中閱讀,我碰到代理/ MailboxProcessors的話題來了這可以用來實現反應狀態機。 C#5中的新異步/等待功能可以用於在C#中實現類似的東西嗎,還是已經有一些更適合的模擬類?

+0

你能解決斷鏈嗎? – czifro 2017-07-08 02:01:37

+0

@czifro,好的。 – Benjol 2017-07-10 04:50:03

回答

3

原則上,我希望將這些F#API轉換爲C#-plus-async-await會很簡單。

實際上,我不清楚它是否會出現漂亮,醜陋和充滿額外類型的註釋,或者僅僅是非慣用的,並且需要一些API-按摩使它在C#中感覺更像家一樣。我認爲陪審團一直到有人做這項工作並嘗試。 (我認爲在等待的CTP中沒有這樣的樣本。)

+2

下載了CTP。現在我將繼續通過嘗試擴大我的無知:) – Benjol 2010-11-02 06:57:58

+0

我看到你的超級分離使它成爲樣品,恭喜:) – Benjol 2010-11-02 10:48:12

+1

哎唷!這對我來說太難了:( – Benjol 2010-11-02 12:40:53

11

由於一些非常可怕的黑客攻擊,您可以使用來自C#的MailboxProcessor類型,使用async。一些困難是該類型使用了一些F#特有的功能(可選參數是選項,函數是FSharpFunc類型等)

從技術上講,最大的區別是F#異步是dealyed而C#異步創建一個已經運行的任務。這意味着要從C#構建F#異步,您需要編寫一個方法,該方法需要unt -> Task<T>並創建Async<T>。我寫了一個blog post that discusses the difference

Anwyay,如果你想嘗試,這裏是一些代碼,你可以使用:

static FSharpAsync<T> CreateAsync<T>(Func<Task<T>> f) 
{ 
    return FSharpAsync.FromContinuations<T>(
    FuncConvert.ToFSharpFunc< 
     Tuple< FSharpFunc<T, Unit>, 
      FSharpFunc<Exception, Unit>, 
      FSharpFunc<OperationCanceledException, Unit> >>(conts => { 
    f().ContinueWith(task => { 
     try { conts.Item1.Invoke(task.Result); } 
     catch (Exception e) { conts.Item2.Invoke(e); } 
    }); 
    })); 
} 

static void MailboxProcessor() { 
    var body = FuncConvert.ToFSharpFunc< 
       FSharpMailboxProcessor<int>, 
       FSharpAsync<Unit>>(mbox => 
    CreateAsync<Unit>(async() => { 
     while (true) { 
     var msg = await FSharpAsync.StartAsTask 
      (mbox.Receive(FSharpOption<int>.None), 
      FSharpOption<TaskCreationOptions>.None, 
      FSharpOption<CancellationToken>.None); 
     Console.WriteLine(msg); 
     } 
     return null; 
    })); 
    var agent = FSharpMailboxProcessor<int>.Start(body, 
       FSharpOption<CancellationToken>.None); 
    agent.Post(1); 
    agent.Post(2); 
    agent.Post(3); 
    Console.ReadLine(); 
} 

正如你所看到的,這看起來很可怕:-)。

  • 原則上,它可能是可以寫入的MailboxProcessor類型C#友好包裝(只是提取此代碼醜陋位),但也存在一些問題。

  • 在F#中,您經常使用尾遞歸異步實現郵箱處理器中的狀態機。如果你用C#編寫相同的東西,你最終會得到StackOverflow,所以你需要編寫可變狀態的循環。

  • 完全可以在F#中編寫代理並從C#調用它。這只是將來自F#的C#友好接口公開(使用Async.StartAsTask方法)。

+0

哎唷,我的眼睛:)'任務 - >異步'正是我被卡住了,所以我會看看那個。如何重寫在C#中的MailboxProcessor,或者它會不值得的努力,因爲你的第二點關於遞歸? – Benjol 2010-11-02 13:53:29

+0

@ Benjol - 我在C#中寫了一個類似的類型。它大約有300行代碼。區別在於簡化的API。 – ChaosPandion 2010-11-02 13:56:54

+0

@ Benjol:我認爲用C#重寫MailboxProcessor也是一個選擇。要獲得鎖定和同步的權利並不容易(特別是'TryScan'方法),但我認爲它應該可以工作(您總是可以避免遞歸,但是在_state machines_的情況下代碼看起來相當糟糕,所以很不幸,如果這是用戶必須寫的) – 2010-11-02 13:57:54

0

您可能會看看Stact。它有一段時間沒有更新,但如果你想用更好的C#支持做一些事情,你可能會發現它是一個很好的起點。不過,我認爲它不是最新的async/await。