この質問は、私が完全には理解していない 2 つのトピックを組み合わせたものです
F# の asyncに関する論文を読んで、リアクティブ ステート マシンの実装に使用できる Agents/MailboxProcessors のトピックに出会いました。C#5 の新しい async/await 機能を使用して、C# で同様のものを実装できますか?それとも、より適したアナログが既に存在しますか?
この質問は、私が完全には理解していない 2 つのトピックを組み合わせたものです
F# の asyncに関する論文を読んで、リアクティブ ステート マシンの実装に使用できる Agents/MailboxProcessors のトピックに出会いました。C#5 の新しい async/await 機能を使用して、C# で同様のものを実装できますか?それとも、より適したアナログが既に存在しますか?
少し恐ろしいハッキングで、MailboxProcessor
C# を使用して型を使用できますasync
。いくつかの問題は、型がいくつかの F# 固有の機能を使用していることです (オプションの引数はオプション、関数はFSharpFunc
型など)。
技術的には、最大の違いは、F# の async が処理され、C# の async が既に実行中のタスクを作成することです。つまり、C# から F# async を構築するには、 を取得して作成するメソッドをunt -> Task<T>
作成する必要がありますAsync<T>
。この違いについて説明するブログ記事を書きました。
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();
}
ご覧のとおり、これは本当にひどいものに見えます :-)。
原則として、この型の C# に適したラッパーを作成することは可能ですがMailboxProcessor
(このコードから醜い部分を抽出するだけです)、いくつかの問題があります。
F# では、末尾再帰非同期を使用して、メールボックス プロセッサにステート マシンを実装することがよくあります。C# で同じことを書くと最終的にはStackOverflow
になるので、変更可能な状態でループを記述する必要があります。
F# でエージェントを作成し、C# から呼び出すことは完全に可能です。これは、(メソッドを使用して) F# から C# に適したインターフェイスを公開するだけの問題ですAsync.StartAsTask
。
原則として、これらの F# API を C#-plus-async-await に変換するのは簡単だと思います。
実際には、それが美しいものになるのか、それとも醜く余分な型注釈でいっぱいになるのか、それとも単純に慣用的ではなく、C# でより使いやすくするために何らかの API マッサージが必要になるのかはわかりません。誰かが仕事をして試してみるまで、陪審員は出ていないと思います。(await CTP にはそのようなサンプルはないと思います。)
Stactを見てみてはいかがでしょうか。しばらくの間更新されていませんが、C#のサポートが少し優れているものを作成したい場合は、出発点として適していると思われるかもしれません。ただし、async/awaitは最新ではないと思います。