我认为 F# 代理使用MailboxProcessor
和 CCR 实现了不同的编程模型,但我相信两者都同样强大,尽管肯定有问题可以用一个或另一个更好地解决,所以最好有另一个库F# 围绕邮箱构建。基于 CCR 的编程模型可能在各种基于连接演算的语言中描述得更清楚,例如COmega(这是一个旧的 MSR 项目)。
例如,您可以比较使用 COmega 和 F# 代理的一个地方缓冲区的实现:
public class OnePlaceBuffer {
private async empty();
private async contains(string s);
public OnePlaceBuffer() { empty(); }
public void Put(string s) & empty() {
contains(s);
}
public string Get() & contains(string s) {
empty();
return s;
}
}
在此示例中,异步方法的行为类似于邮箱(因此其中有四个:empty
、contains
和当你从一个完整的缓冲区中获取时)。在 F# 中,您可以使用和编写:Put
Get
MailboxProcessor
type Message<'T> =
| Put of 'T * AsyncReplyChannel<unit>
| Get of AsyncReplyChannel<'T>
MailboxProcessor.Start(fun agent ->
let rec empty = agent.Scan(function
| Put(v, repl) -> repl.Reply(); Some(full(v))
| _ -> None)
and full v = agent.Scan(function
| Get repl -> repl.Reply(v); Some(empty)
| _ -> None)
empty )
这两个实现表达了相同的想法,但方式略有不同。在 F# 中,empty
和full
是两个函数,表示代理的不同状态,发送给代理的消息表示代理状态的不同方面(待处理的工作)。在 COmega 实现中,程序的所有状态都由邮箱捕获。
我想将代理的状态与需要处理的即时消息分开可能会更容易考虑 F# MailboxProcessor
,但这只是一个直接的想法,没有任何理由......
最后,MailboxProcessor
在 F# 中使用的实际应用程序中,您很可能会使用大量它们,并且它们将以某种方式连接起来。例如,实现流水线是使用多个MailboxProcessor
实例的应用程序的一个很好的例子(当然,它们都有一些与之关联的简单运行的异步工作流)。有关示例,请参见本文。