Как четко структурировать зависимости между каналами core.async?

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

Вот несколько потенциальных решений, с которыми я столкнулся:

  • График Prismatic - кажется разумным, хотя я не тестировал его с каналами core.async; тот факт, что это требует использования fnk для меня это немного обескураживает, потому что это требует покупки в их DSL для определения функций, но если это лучшее решение, то я не против.
  • Ячейки Javelin - только для ClojureScript (в настоящее время) и используют FRP вместо CSP в качестве реализации, но он очень хорошо справляется с моделированием зависимостей между вычислениями с помощью ячеек формулы.
  • Onyx - создан для распределенных вычислений (как конкурент Apache Storm и т. Д.), Но имеет абстракцию "рабочего процесса", которая обрабатывает зависимости между вычислениями и работает с core.async. Похоже, это наиболее близко подходит к моей проблемной области, но я не уверен, что мне нужны дополнительные возможности всех функций управления кластером.

Каково каноническое решение этой проблемы?

Редактировать: добавлен Оникс

2 ответа

Решение

Я не думаю, что есть канонический способ решить эту проблему, core.async настолько нов, что мало кто его попробовал. Если бы мне пришлось выбирать между вашими тремя вариантами, я бы выбрал Graph, он некоторое время был развернут и протестирован в производстве, и вам не нужен Clojurescript для его запуска. Если вы заинтересованы в решении FRP, взгляните на Java Reactive Extensions, привязки Clojure для него существуют в RxClojure.

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

Если вы просто хотите, чтобы поток или блок go зависели от результатов, генерируемых в другой части вашей системы, я бы предложил просто использовать примитивы core.async без каких-либо дополнительных библиотек.

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

Как вы можете видеть в следующем примере, сделать вычисление в зависимости от действия, выполненного в другом потоке, очень легко.

(let [c (chan)]
  (thread (>!! c “hello”))
  (assert (= “hello” (<!! c)))
  (close! c)

Есть также более сложные механизмы, доступные. Alts!! Функция обеспечивает возможность ожидания на нескольких каналах одновременно. Несколько разных вкусов pipeline Функция позволяет вам моделировать параллелизм в потоке данных.

Существуют ли какие-либо конкретные проблемы, с которыми вы можете столкнуться, которые не могут быть четко выражены с помощью встроенных функций?

Для #3 выше, onyx-local-rt может соответствовать всем требованиям:

onyx-local-rt - это альтернативная среда выполнения для Onyx, которая выполняет задания в чистой, детерминированной среде. Эта среда выполнения только локальная и не работает в распределенном режиме. Это инкубационное хранилище, означающее, что этот код будет перемещен в ядро ​​Onyx позже.

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