Я думаю, что агенты 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
, Put
и Get
), а тела ведут себя как обработчики, которые будут срабатывать при комбинации почтовых ящиков содержит значение (т.е. когда вы помещаете в пустой буфер или когда вы получаете из полного буфера). В F # вы можете использовать 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
(с которыми, конечно, связан простой асинхронный рабочий процесс, работающий с ними). См. эту статью для примера.