Мне интересно выяснить, можно ли решить проблему производителя-потребителя, когда есть несколько продуктов и несколько потребителей, без использования присваивания, то есть с использованием функционального стиля программирования? Как?

Проблема производитель-потребитель

Благодарность

3
StackUnderflow 5 Авг 2009 в 22:30

5 ответов

Лучший ответ

Да, вы можете сделать это довольно хорошо с помощью передачи сообщений в Concurrent ML. Не откладывайте возраст системы; и статьи Джона Реппи являются отличным руководством по этой теме. Прекрасная штука!

3
Norman Ramsey 5 Авг 2009 в 19:48

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

Хотя можно оценивать несколько частей функции параллельно, как в Haskell ` `par оператор, это не то же самое, что проблема производитель-потребитель, и поэтому я не думаю, что вы сможете решить это функционально.

3
bdonlan 5 Авг 2009 в 19:01

Да. Ознакомьтесь с функциональным реактивным программированием (FRP), которое связано с Concurrent ML (предложение Нормана), но является чисто функциональным. Семантика FRP очень "параллельна", имея простую, точную, детерминированную, функциональную семантическую модель (функции времени).

Изменить: я процитировал здесь «параллельный», потому что я не имел в виду обычное рабочее (ориентированное на реализацию) понятие параллелизма, которое является императивным и недетерминированным, что препятствует практичное и достоверно правильное рассуждение.

3
Conal 11 Апр 2016 в 18:32

Все реализации производителя-потребителя в SML, которые я видел, были вынуждены полагаться на ref (чтобы поддерживать очередь "спящих" элементов), поэтому я был бы склонен сказать "нет" .

1
Amber 5 Авг 2009 в 18:33

Есть много способов решить эту проблему; у каждого есть свои недостатки.

Например, «put» может каждый раз порождать новый поток. Таким образом, вам вообще не понадобится буфер. Если поступает много запросов, вы создаете много потоков, пока ваш процессор не будет больше занят переключением между потоками, чем их фактическим выполнением. Но это просто переносит проблему из вашего кода в ОС: в определенный момент вам всегда нужно синхронизировать доступ к переменной в памяти. ОС должна поддерживать список потоков, и доступ к этому списку должен быть синхронизирован.

Либо вы хотите ограничить количество потоков (тогда «put» должен иметь возможность читать переменную, в то время как потоки могут завершаться одновременно и уменьшать ее -> снова синхронизированный доступ). Или вы рискуете исчерпать ресурсы из-за слишком большого количества потоков.

Вы можете отправить сообщение, когда вызывается "put", и потребители могут слушать сообщение. Но это всего лишь сложный способ реализации «ожидания» потоков. И вам нужен способ убедиться, что сообщение получает только один потребитель. Опять же, вам понадобится некоторая синхронизированная структура данных.

Итак, в конце концов, проблема заключается не в назначении, а в параллельном доступе к одной переменной, и как бы вы ни старались, для любой реализации продукта-потребителя вы должны иметь возможность сделать это (или все будет быть однопроходным).

1
Aaron Digulla 5 Авг 2009 в 18:38