這個問題結合了兩個主題,我不完全理解代理/ MailboxProcessor在C#中使用新的異步/等待
通過paper約異步F#中閱讀,我碰到代理/ MailboxProcessors的話題來了這可以用來實現反應狀態機。 C#5中的新異步/等待功能可以用於在C#中實現類似的東西嗎,還是已經有一些更適合的模擬類?
這個問題結合了兩個主題,我不完全理解代理/ MailboxProcessor在C#中使用新的異步/等待
通過paper約異步F#中閱讀,我碰到代理/ MailboxProcessors的話題來了這可以用來實現反應狀態機。 C#5中的新異步/等待功能可以用於在C#中實現類似的東西嗎,還是已經有一些更適合的模擬類?
原則上,我希望將這些F#API轉換爲C#-plus-async-await會很簡單。
實際上,我不清楚它是否會出現漂亮,醜陋和充滿額外類型的註釋,或者僅僅是非慣用的,並且需要一些API-按摩使它在C#中感覺更像家一樣。我認爲陪審團一直到有人做這項工作並嘗試。 (我認爲在等待的CTP中沒有這樣的樣本。)
由於一些非常可怕的黑客攻擊,您可以使用來自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
方法)。
哎唷,我的眼睛:)'任務 - >異步
@ Benjol - 我在C#中寫了一個類似的類型。它大約有300行代碼。區別在於簡化的API。 – ChaosPandion 2010-11-02 13:56:54
@ Benjol:我認爲用C#重寫MailboxProcessor也是一個選擇。要獲得鎖定和同步的權利並不容易(特別是'TryScan'方法),但我認爲它應該可以工作(您總是可以避免遞歸,但是在_state machines_的情況下代碼看起來相當糟糕,所以很不幸,如果這是用戶必須寫的) – 2010-11-02 13:57:54
您可能會看看Stact。它有一段時間沒有更新,但如果你想用更好的C#支持做一些事情,你可能會發現它是一個很好的起點。不過,我認爲它不是最新的async/await。
你能解決斷鏈嗎? – czifro 2017-07-08 02:01:37
@czifro,好的。 – Benjol 2017-07-10 04:50:03