Использовать Post или PostAndAsyncReply с F # MailboxProcessor? - PullRequest
5 голосов
/ 15 декабря 2011

Я видел разные фрагменты, демонстрирующие сообщение Put, которое возвращает unit с F # 's MailboxProcessor.В некоторых случаях используется только метод Post, в то время как другие используют PostAndAsyncReply, причем канал ответа немедленно отвечает после обработки сообщения.При проведении некоторого тестирования я обнаружил значительную задержку во время ожидания ответа, поэтому кажется, что если вам не нужен реальный ответ, вы должны использовать Post.

Примечание: я начал спрашивать об этом в другая тема , но посчитал полезным опубликовать полный вопрос.В другой теме Томас Петричек упомянул, что в канале ответа можно использовать механизм ожидания, чтобы гарантировать, что вызывающий абонент задерживается до обработки сообщения Put.

Использует ли PostAndAsyncReply помощь в упорядочении сообщений или являетсяэто просто заставить паузу, пока не обработано первое сообщение?С точки зрения производительности Post представляется правильным решением.Это точно?

Обновление:

Я только что подумал о причине, по которой PostAndAsyncReply может понадобиться в примере BlockingQueueAgent :Scan используется для поиска Get сообщений, когда очередь заполнена, поэтому вы не хотите Put и затем Get до завершения предыдущего Put.

Ответы [ 2 ]

4 голосов
/ 01 июля 2013

Мой совет - спроектировать вашу систему так, чтобы вы могли использовать Post как можно больше.

Эта технология была разработана для асинхронного параллелизма, цель которого - запускать и забывать сообщения. Идея ожидания ответа идет прямо вразрез с этим.

3 голосов
/ 16 декабря 2011

Я думаю, что я в целом согласен с вашим резюме - имеет смысл, что PostAndAsyncReply медленнее, чем Post, поэтому если вызывающей стороне не нужно получать уведомление от агента при выполнении операции (например, при вводе значения в очередь), это определенно должно предоставить способ сделать это, используя Post. Тот факт, что PostAndAsyncReply намного медленнее, вероятно, означает, что некоторые агенты должны предоставить оба варианта и позволить вызывающему абоненту решить.

Что касается конкретного примера BlockingQueueAgent (или аналогичного примера, который я использовал для реализации одноразового буфера), типичным применением агента является решение проблемы потребитель-производитель. В проблеме «потребитель-производитель» мы хотим заблокировать производителя, когда очередь заполнена, и заблокировать потребителя, когда она пуста. .NET BlockingCollection поддерживает только синхронную блокировку, что немного плохо (то есть может блокировать весь пул потоков).

Используя BlockingQueueAgent, который отправляет сообщение Put, используя PostAndAsyncReply, мы можем ожидать асинхронного добавления элемента в очередь (поэтому он блокирует производителя, но без блокировки потоков!) Пример типичного используется конвейер обработки изображений , который я написал некоторое время назад. Вот один фрагмент из этого:

// Phase 2: Scale to a thumbnail size and add frame
let scalePipelinedImages = async {
   while true do 
     let! info = loadedImages.AsyncGet()
     scaleImage info
     do! scaledImages.AsyncAdd(info) }

Этот цикл повторно получает изображение из очереди loadedImages, выполняет некоторую обработку и записывает результат в scaledImages. Блокировка с использованием очереди (как при чтении, так и при записи) контролирует параллелизм, поэтому шаги конвейера выполняются параллельно, но при этом не загружается все больше и больше изображений, если конвейер не может обрабатывать их с требуемой скоростью.

...