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

Ben*_*jol 7 c# f# agent c#-to-f# async-await

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

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

Tom*_*cek 11

有一点非常可怕的黑客攻击,你可以使用MailboxProcessorC#中的类型async.一些困难是该类型使用一些F#特定功能(可选参数是选项,功能是FSharpFunc类型等)

从技术上讲,最大的区别是F#async被分析,而C#async创建一个已经运行的任务.这意味着要从C#构造F#异步,您需要编写一个接受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();
}
Run Code Online (Sandbox Code Playgroud)

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

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

  • 在F#中,您经常使用尾递归异步来实现邮箱处理器中的状态机.如果你在C#中编写相同的东西,你最终会得到StackOverflow,所以你需要编写具有可变状态的循环.

  • 完全可以在F#中编写代理并从C#中调用它.这仅仅是(使用从F#曝光C# -友好界面的物质Async.StartAsTask的方法).


Bri*_*ian 3

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

在实践中,我不清楚它是否会变得漂亮,或者丑陋并且充满额外的类型注释,或者只是不惯用并且需要一些 API 按摩以使其在 C# 中感觉更自在。我认为在有人完成工作并尝试之前,评判是没有定论的。(我认为等待CTP中没有这样的样本。)

  • 下载了CTP。现在我将继续尝试扩大我的无知:) (2认同)