2010-11-02 33 views
7

这个问题结合了两个主题,我不完全理解代理/ MailboxProcessor在C#中使用新的异步/等待

通过paper约异步F#中阅读,我碰到代理/ MailboxProcessors的话题来了这可以用来实现反应状态机。 C#5中的新异步/等待功能可以用于在C#中实现类似的东西吗,还是已经有一些更适合的模拟类?

+0

你能解决断链吗? – czifro 2017-07-08 02:01:37

+0

@czifro,好的。 – Benjol 2017-07-10 04:50:03

回答

3

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

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

+2

下载了CTP。现在我将继续通过尝试扩大我的无知:) – Benjol 2010-11-02 06:57:58

+0

我看到你的超级分离使它成为样品,恭喜:) – Benjol 2010-11-02 10:48:12

+1

哎唷!这对我来说太难了:( – Benjol 2010-11-02 12:40:53

11

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

从技术上讲,最大的区别是F#异步是dealyed而C#异步创建一个已经运行的任务。这意味着要从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#中,您经常使用尾递归异步实现邮箱处理器中的状态机。如果你用C#编写相同的东西,你最终会得到StackOverflow,所以你需要编写可变状态的循环。

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

+0

哎唷,我的眼睛:)'任务 - >异步'正是我被卡住了,所以我会看看那个。如何重写在C#中的MailboxProcessor,或者它会不值得的努力,因为你的第二点关于递归? – Benjol 2010-11-02 13:53:29

+0

@ Benjol - 我在C#中写了一个类似的类型。它大约有300行代码。区别在于简化的API。 – ChaosPandion 2010-11-02 13:56:54

+0

@ Benjol:我认为用C#重写MailboxProcessor也是一个选择。要获得锁定和同步的权利并不容易(特别是'TryScan'方法),但我认为它应该可以工作(您总是可以避免递归,但是在_state machines_的情况下代码看起来相当糟糕,所以很不幸,如果这是用户必须写的) – 2010-11-02 13:57:54

0

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