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

时间:2010-11-02 05:44:44

标签: c# f# agent c#-to-f# async-await

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

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

3 个答案:

答案 0 :(得分:11)

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

从技术上讲,最大的区别是F#async被分析,而C#async创建一个已经运行的任务。这意味着要从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#中,您经常使用tail-recursive asyncs来实现邮箱处理器中的状态机。如果你在C#中编写相同的东西,你最终会获得StackOverflow,所以你需要编写具有可变状态的循环。

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

答案 1 :(得分:3)

原则上,我希望将这些F#API转换为C#-plus-async-await是直截了当的。

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

答案 2 :(得分:0)

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