Почтовый ящик F # против MailboxProcessor - PullRequest
0 голосов
/ 13 декабря 2011

Я заметил, что тип почтового ящика инкапсулирован и может использоваться только с использованием MailboxProcessor.

Это означает, что для того, чтобы иметь агента, которому я могу публиковать сообщения, я вынужден иметь один почтовый ящик одного типа (или использовать существующий MailboxProcessor экзотическим способом).

Должен ли я понимать, что наличие нескольких почтовых ящиков для одного рабочего процесса по своей сути приведет к плохому дизайну? Ccr явно дает вам этот уровень свободы.

Edit: Как отметил Дэниел, если кто-то хочет отправить несколько типов сообщений, DU элегантно решает проблему - и я не делал этого раньше.

Но вопрос в том, не делает ли это запах кода? Не приведет ли к тому, что добавление дополнительных типов сообщений, отправленных агенту с течением времени, приведет к тому, что у вас будет слишком много обязанностей? Иногда я думаю, что было бы важно всегда инкапсулировать типы сообщений, которые агент использует за интерфейсом, чтобы эта информация никогда не передавалась.

Ответы [ 4 ]

4 голосов
/ 13 декабря 2011

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

1 голос
/ 13 декабря 2011

Я не думаю, что вы когда-нибудь сможете успешно работать с почтовым ящиком, используя только один тип сообщения, если только вы не используете что-то типа ISubject из Reactive Extensions.Сообщения приходят в разных формах, и все они важны.Вот два основных примера, которые я могу вспомнить:

  1. Управляющие сообщения - обозначают операции, которые почтовый ящик должен выполнять, такие как очистка его очереди, поиск определенных сообщений, завершение работы, раскрутка дочерних процессов и т. Д.
  2. Сообщения данных - отправка и получение (Put / Get) - это основные типы.

Вы правы, полагая, что вы, скорее всего, захотите ограничить сообщения данными доопределенный тип, но технически DU - это один тип со многими альтернативами.Если бы вы выбрали тот же подход, что и Лука с его первоначальным динамическим подходом в L'Agent, я думаю, что и он, и я согласились бы с тем, что слишком много типов в одном почтовом ящике - это сложная задача.

1 голос
/ 13 декабря 2011

Как правило, тип сообщения - это различающееся объединение, которое допускает различные виды сообщений в одном почтовом ящике.Разве это не работает в вашем случае?

0 голосов
/ 20 июня 2012

Думаю, я нашел то, что искал.Я слушал выступление Рича Хики (мы уже там) по крайней мере 5 раз, и я верю, что его подход решает многие проблемы дизайна, которые у меня были.Очевидно, что это может быть реализовано с использованием почтовых ящиков F # или ссылок CAS.

Я действительно рекомендую это и был бы рад услышать некоторые отзывы.

...