13

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

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

4

2 回答 2

18

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

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

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

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

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# 的下一个版本中,当您能够使用 C#await关键字处理任务时,它会更好。

于 2011-04-07T20:45:10.937 回答
0

此解决方案需要 C#“异步 CTP”,但请使用新的 async/await 查看 C# 中的 Agent/MailboxProcessor

于 2011-04-07T13:21:06.657 回答