我想在F#中实现CCR框架端口的概念(因为.Net 4.0不正式支持CCR)。我知道可以使用F#中的 MailboxProcessor 类来执行此操作。 这对于简单的接收 Arbiters非常有效,但我需要 Interleave Arbiter的概念,即我想控制哪些消息是专门处理的,哪些是同时处理的。 到目前为止,我不知道在F#中实现这一点,我将非常感谢你的帮助。
答案 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一起使用),因为对此消息的响应只会在所有的读操作都完成了。此外,“读取”所代表的“读取”计数将被移动到这个新的内部邮箱,因为该状态将被此内部邮箱封装。