【问题标题】:MailboxProcessor<T> from C#来自 C# 的邮箱处理器<T>
【发布时间】:2011-04-07 13:16:49
【问题描述】:

您是否尝试过在 C# 中使用 T 的 MailboxProcessor?你能发布示例代码吗?

你如何开始一个新的,向它发布消息,以及你如何处理它们?

【问题讨论】:

    标签: c#-4.0 concurrency f# c#-to-f# mailboxprocessor


    【解决方案1】:

    虽然您可以直接从 C# 使用 MailboxProcessor&lt;T&gt;(使用 C# async 扩展名),正如我在其他答案中指出的那样,但这并不是一件好事 - 我主要是出于好奇而写的。

    MailboxProcessor&lt;T&gt; 类型被设计为在 F# 中使用,因此它不适合 C# 编程模型。您可能可以为 C# 实现类似的 API,但它不会那么好(当然不是在 C# 4.0 中)。 TPL DataFlow library (CTP) 为未来的 C# 版本提供了类似的设计。

    目前,最好的办法是在 F# 中使用 MailboxProcessor&lt;T&gt; 实现代理,并通过使用 Task 使其对 C# 的使用友好。这样,您可以在 F# 中实现代理的核心部分(使用尾递归和异步工作流),然后在 C# 中组合和使用它们。

    我知道这可能无法直接回答您的问题,但我认为值得举一个例子 - 因为这确实是将 F# 代理 (MailboxProcessor) 与 C# 结合的唯一合理方法。 最近写了一个简单的“聊天室”demo,这里举个例子:

    type internal ChatMessage = 
      | GetContent of AsyncReplyChannel<string>
      | SendMessage of string
    
    type ChatRoom() = 
      let agent = Agent.Start(fun agent -> 
        let rec loop messages = async {
          // Pick next message from the mailbox
          let! msg = agent.Receive()
          match msg with 
          | SendMessage msg -> 
              // Add message to the list & continue
              let msg = XElement(XName.Get("li"), msg)
              return! loop (msg :: messages)
    
          | GetContent reply -> 
              // Generate HTML with messages
              let html = XElement(XName.Get("ul"), messages)
              // Send it back as the reply
              reply.Reply(html.ToString())
              return! loop messages }
        loop [] )
      member x.SendMessage(msg) = agent.Post(SendMessage msg)
      member x.AsyncGetContent() = agent.PostAndAsyncReply(GetContent) 
      member x.GetContent() = agent.PostAndReply(GetContent)
    

    到目前为止,这只是一个标准的 F# 代理。现在,有趣的是以下两个方法,它们将GetContent 公开为可从 C# 使用的异步方法。该方法返回Task对象,可以在C#中以通常的方式使用:

      member x.GetContentAsync() = 
        Async.StartAsTask(agent.PostAndAsyncReply(GetContent))
    
      member x.GetContentAsync(cancellationToken) = 
        Async.StartAsTask
         ( agent.PostAndAsyncReply(GetContent), 
           cancellationToken = cancellationToken )
    

    这将在 C# 4.0 中合理使用(使用标准方法,例如 Task.WaitAll 等),并且当您能够使用 C# await 关键字时,在 C# 的下一个版本中它会更好处理任务。

    【讨论】:

    • 感谢您的详细解答。我会试一试!缺少一件——来自 C# 4.0 的实际用法。
    【解决方案2】:

    此解决方案需要 C#“异步 CTP”,但请查看 Agent/MailboxProcessor in C# using new async/await

    【讨论】:

    • 问题专门针对 C# 4.0,因为我手忙脚乱。我会为此使用 F#,但我现在还不能。 Async CTP 是否有上线许可证?
    • 正如 Tomas P. 指出的那样,这个问题的症结在于导致 StackOverflowException 的尾递归调用。我正在寻找替代品。
    • @GregC,不,它没有上线许可证。它只是一个预览,顾名思义,你不应该在生产中使用它
    • 很难忘记强大的编程范式。一旦你知道了,你就拒绝用旧的简单方法来实现。
    猜你喜欢
    • 2015-06-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-05-03
    • 2014-01-26
    • 2020-08-19
    • 2012-07-19
    • 2010-10-04
    相关资源
    最近更新 更多