在F#中实现CCR交织仲裁器

时间:2011-04-28 15:32:59

标签: f# ccr

我想在F#中实现CCR框架端口的概念(因为.Net 4.0不正式支持CCR)。我知道可以使用F#中的 MailboxProcessor 类来执行此操作。 这对于简单的接收 Arbiters非常有效,但我需要 Interleave Arbiter的概念,即我想控制哪些消息是专门处理的,哪些是同时处理的。 到目前为止,我不知道在F#中实现这一点,我将非常感谢你的帮助。

2 个答案:

答案 0 :(得分:1)

我对CCR不太熟悉,但我会尝试回答 - 我的理解是 interleave arbiter 的行为有点像ReaderWriterLock。也就是说,您可以指定一些可以并行运行的操作(读取)和一些独占(写入)的操作。

以下代理是实现它的一种方法(未经过测试,但是类型检查:-))。代理公开了两个供公众使用的操作。最后一个是内部的:

type Message<'T> =
  | PerformReadOperation of ('T -> Async<unit>)
  | PerformWriteOperation of ('T -> Async<'T>)
  | ReadOperationCompleted
  • 通过发送代理PerformReadOperation,您将为其提供一个应该使用状态运行(一次)的操作,并且可能与其他读取操作并行。

  • 通过发送代理PerformWriteOperation,您将为其提供计算新状态的操作,并且必须在所有读取操作完成后执行。 (如果你正在使用不可变状态,这会使事情更简单 - 你不必等到读者完成!但下面的实现实现了等待。)

代理以一些初始状态开始:

let initial = // initial state

代理的其余部分使用两个循环实现:

let interleaver = MailboxProcessor.Start(fun mbox ->

  // Asynchronously wait until all read operations complete
  let rec waitUntilReadsComplete reads = 
    if reads = 0 then async { return () }
    else mbox.Scan(fun msg ->
      match msg with
      | ReadOperationCompleted -> Some(waitUntilReadsComplete (reads - 1))
      | _ -> None)

  let rec readingLoop state reads = async {
    let! msg = mbox.Receive()
    match msg with
    | ReadOperationCompleted ->
        // Some read operation completed - decrement counter
        return! readingLoop state (reads - 1) 
    | PerformWriteOperation(op) ->
        do! waitUntilReadsComplete reads
        let! newState = op state
        return! readingLoop newState 0
    | PerformReadOperation(op) ->
        // Start the operation in background & increment counter
        async { do! op state
                mbox.Post(ReadOperationCompleted) }
        |> Async.Start
        return! readingLoop state (reads + 1) }
  readingLoop initial 0)

答案 1 :(得分:1)

只是添加Tomas建议的解决方案,以防您不希望将“ReadOperationCompleted”消息暴露给邮箱的消费者(因为此消息是内部的,并且在当前实现中可以由任何消费者发送邮箱)可以在主邮箱处理器功能内创建一个单独的邮箱,它将接受两条消息:ReadOperationCompleted和WaitForReadCompleted(这一个将与主邮箱的PostAndAsyncReply一起使用),因为对此消息的响应只会在所有的读操作都完成了。此外,“读取”所代表的“读取”计数将被移动到这个新的内部邮箱,因为该状态将被此内部邮箱封装。