8

This question combines two topics I don't fully understand

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?

4

3 回答 3

11

通过一些非常可怕的黑客攻击,您可以使用MailboxProcessorC# 中的类型 using 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();
}

正如你所看到的,这看起来真的很可怕:-)。

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

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

  • 完全可以用 F# 编写代理并从 C# 调用它。这只是从 F# 暴露 C# 友好接口的问题(使用Async.StartAsTask方法)。

于 2010-11-02T13:43:58.043 回答
3

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

在实践中,我不清楚它是否会变得漂亮,或者丑陋并且充满额外的类型注释,或者只是不习惯并且需要一些 API 按摩以使其在 C# 中感觉更自在。我认为陪审团已经出局,直到有人完成工作并进行尝试。(我认为 await CTP 中没有这样的样本。)

于 2010-11-02T05:54:19.017 回答
0

您可能会看一下Stact。它已经有一段时间没有更新了,但是如果你想用更好的 C# 支持来制作一些东西,你可能会发现它是一个很好的起点。不过,我认为它不是最新的 async/await。

于 2012-04-03T03:12:28.123 回答