Как четко структурировать зависимости между каналами 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 позже.