C#中的Agent / MailboxProcessor使用新的async / await

这个问题结合了我不完全理解的两个主题

通过阅读关于F#中的异步的文章 ,我遇到了Agent / MailboxProcessors的主题,它可用于实现被动状态机。 是否可以使用C#5中的新异步/等待function来实现C#中类似的function,或者是否已经存在更适合的类似模拟?

有一点非常糟糕的黑客攻击,你可以使用async来自C#的MailboxProcessor类型。 一些困难是类型使用一些F#特定function(可选参数是选项,函数是FSharpFunc类型等)

从技术上讲,最大的区别是F#async被分析,而C#async创建一个已经运行的任务。 这意味着要从C#构造F#异步,您需要编写一个带有unt -> Task并创建Async 。 我写了一篇讨论差异的博客文章 。

Anwyay,如果你想进行实验,可以使用以下代码:

 static FSharpAsync CreateAsync(Func> f) { return FSharpAsync.FromContinuations( FuncConvert.ToFSharpFunc< Tuple< FSharpFunc, FSharpFunc, FSharpFunc >>(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, FSharpAsync>(mbox => CreateAsync(async () => { while (true) { var msg = await FSharpAsync.StartAsTask ( mbox.Receive(FSharpOption.None), FSharpOption.None, FSharpOption.None ); Console.WriteLine(msg); } return null; })); var agent = FSharpMailboxProcessor.Start(body, FSharpOption.None); agent.Post(1); agent.Post(2); agent.Post(3); Console.ReadLine(); } 

如你所见,这看起来非常可怕:-)。

  • 原则上,可以为MailboxProcessor类型编写一个C#友好包装器(只是从这段代码中提取丑陋的位),但是有一些问题。

  • 在F#中,您经常使用tail-recursive asyncs来实现邮箱处理器中的状态机。 如果你在C#中编写相同的东西,你最终会获得StackOverflow ,所以你需要编写具有可变状态的循环。

  • 完全可以在F#中编写代理并从C#调用它。 这只是从F#公开C#友好接口(使用Async.StartAsTask方法)。

原则上,我希望将这些F#API转换为C#-plus-async-await是很简单的。

在实践中,我不清楚它是否会变得漂亮,或者丑陋且充满额外的类型注释,或者仅仅是非惯用的并且需要一些API按摩以使其在C#中更有家的感觉。 我认为陪审团已经结束,直到有人做了工作并尝试了。 (我认为在等待CTP中没有这样的样本。)

你可能会看看Stact 。 它在一段时间内没有更新,但如果你想用更好的C#支持做一些事情,你可能会发现它是一个很好的起点。 不过,我不认为它与async / await是最新的。

Interesting Posts