C#中的MailboxProcessor<T>

13

您是否尝试过在C#中使用MailboxProcessor of T?您能否提供示例代码?

如何启动一个新的进程,向其发布消息,并如何处理它们?

2个回答

18

虽然你可以使用C#的async扩展直接使用MailboxProcessor<T>(如我在其他答案中所指出的),但这并不是一个好习惯——我主要是出于好奇心写的。

MailboxProcessor<T>类型是为F#设计的,因此它与C#编程模型不太匹配。你可能可以为C#实现类似的API,但那不会很好(尤其是在C# 4.0中)。TPL DataFlow库(CTP)提供了类似的设计,适用于未来版本的C#。

目前最好的做法是,在F#中使用MailboxProcessor<T>实现代理,并通过使用Task使其对C#友好。这样,你可以使用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 )

使用标准方法(如Task.WaitAll等)从C# 4.0开始,这将是相当可用的,在C#的下一个版本中,您甚至可以使用C# await关键字来处理任务,那时它会更加方便。


谢谢您详细的回答。我会尝试一下!还有一个地方需要补充——实际在C# 4.0中的使用。 - GregC

0

这个问题特别针对C# 4.0,因为我手头的工作需要。我很想用F#来解决这个问题,但目前还不行。Async CTP有go-live许可证吗? - GregC
正如Tomas P.所指出的那样,这个问题的关键在于尾递归调用导致了StackOverflowException。我正在寻找替代方案。 - GregC
@GregC,它没有go-live许可证。正如名称所示,它只是一个预览版,您不应在生产中使用它。 - Thomas Levesque
学会了一种强大的编程范式后,想要放弃它是很难的。一旦掌握,你会拒绝以老式的简单方式来实现事物。 - GregC

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接