代理/邮箱处理器在 C# 中使用新的 async/await [英] Agent/MailboxProcessor in C# using new async/await
问题描述
这个问题结合了我不完全理解的两个主题
通读paper 关于 F# 中的异步,我遇到了 Agents/MailboxProcessors 的话题,它可以用来实现反应式状态机.C#5 中新的 async/await 功能是否可以用于在 C# 中实现类似的东西,或者是否已经有类似的东西更适合?
Reading through a paper about async in F#, I came across the topic of Agents/MailboxProcessors, which can be used to implement reactive state machines. Could the new async/await functionality in C#5 be used to implement something similar in C#, or is there already something analogue that would be better suited?
推荐答案
通过一些非常可怕的黑客攻击,您可以使用 async
使用 C# 中的 MailboxProcessor
类型.一些困难是该类型使用了一些 F# 特定功能(可选参数是选项,函数是 FSharpFunc
类型等)
With a bit of pretty horrible hacking, you can use the MailboxProcessor
type from C# using async
. Some difficulties are that the type uses some F# specific features (optional arguments are options, functions are FSharpFunc
type, etc.)
从技术上讲,最大的区别是 F# async 被处理,而 C# async 创建一个已经在运行的任务.这意味着要从 C# 构造 F# async,您需要编写一个接受 unt ->;任务
并创建Async
.我写了一篇讨论差异的博客文章.
Technically, the biggest difference is that F# async is dealyed while C# async creates a task that is already running. This means that to construct F# async from C#, you need to write a method that takes unt -> Task<T>
and creates Async<T>
. I wrote a blog post that discusses the difference.
Anwyay,如果你想尝试,这里有一些代码你可以使用:
Anwyay, if you want to experiment, here is some code you can use:
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();
}
正如你所看到的,这看起来真的很可怕:-).
As you can see, this looks really horrible :-).
原则上,可以为
MailboxProcessor
类型编写一个 C# 友好的包装器(只需从这段代码中提取丑陋的部分),但存在一些问题.
In principle, it could be possible to write a C# friendly wrapper for the
MailboxProcessor
type (just extract the ugly bits from this code), but there are some problems.
在 F# 中,您经常使用尾递归异步来实现邮箱处理器中的状态机.如果你用 C# 写同样的东西,你最终会得到 StackOverflow
,所以你需要编写具有可变状态的循环.
In F# you often use tail-recursive asyncs to implement the state machine in the mailbox processor. If you write the same thing in C#, you'll eventually get StackOverflow
, so you'd need to write loops with mutable state.
完全可以用 F# 编写代理并从 C# 调用它.这只是从 F# 公开 C# 友好界面的问题(使用 Async.StartAsTask
方法).
It is perfectly possible to write the agent in F# and call it from C#. This is just a matter of exposing C#-friendly interface from F# (using the Async.StartAsTask
method).
这篇关于代理/邮箱处理器在 C# 中使用新的 async/await的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!