Использовать Post или PostAndAsyncReply с F# для MailboxProcessor?

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

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

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

Обновить:

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

2 ответа

Решение

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

Что касается конкретного примера BlockingQueueAgent (или аналогичный, который я использовал для реализации одноразового буфера), типичное применение агента - решение проблемы потребитель-производитель. В проблеме потребитель-производитель мы хотим заблокировать производителя, когда очередь заполнена, и заблокировать потребителя, когда она пуста. Сеть 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, Блокировка с использованием очереди (как при чтении, так и при записи) управляет параллелизмом, так что шаги конвейера выполняются параллельно, но не продолжают загружать все больше и больше изображений, если конвейер не может обрабатывать их с требуемой скоростью.

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

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

Другие вопросы по тегам