Кажется, не требуется>!! или <!! в Clojurescript?

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

(ns shopping-2.core
  (:require [cljs.core.async :as async :refer [>!! <!! put! chan <! close! <!!]]))

(let [c (chan)]
  (>!! c "hello")
  (.write js/document (<!! c))
  (close! c))

Ошибка JavaScript, которую я получаю, это:

Uncaught TypeError: Cannot call method 'call' of undefined 

У меня была эта ошибка до того, когда я забыл: см. chan in (если я просто открою канал, а затем закройте его снова, программа работает нормально)

Однако этот код, кажется, задыхается, когда я хочу использовать макросы <!! или >!!.

Ответ 1

Есть некоторые отличия от того, что доступно в clojurescript из версии clojure core.async.

Поскольку clojure на JVM имеет реальные потоки, он предоставляет как шаблоны concurrency с реальными потоками, так и с блоками go:

  • Реальные потоки используют макрос thread для приложения core.async magic и его макросы и функции concurrency заканчиваются двумя ошибками, например <!!, >!!, alt!! и alts!!.

  • Инверсия потоков управления (поддельные потоки) используют макрос go, чтобы заключить магию core.async и использует функции с одним ударом в конце, например <!, >!, alt! и alts!.

В clojurescript (который работает в js) нет реальных потоков, поэтому доступны только потоки IoC (инверсия управления), что означает, что вы должны использовать второй вариант конструкций concurrency.

Ваш пример будет выглядеть следующим образом:

(ns shopping-2.core
  (:require-macros [cljs.core.async.macros :refer [go]])
  (:require [cljs.core.async :as async :refer [put! chan <! >! close!]]))

(go
  (let [c (chan)]
    (>! c "hello")
    (.write js/document (<! c))
    (close! c)))

Во всяком случае, этот пример имеет проблему concurrency, так как функции <! >! блокируются, и вы помещаете в chan в ту же процедуру, процедура будет блокироваться в инструкции (>! c "hello") и никогда не будет читать, определенно голодают вашу программу.

Вы можете исправить это, используя put! fn, который помещается без блокировки или эффективно запускает эти инструкции в разных процедурах, которые, как я думаю, лучше показывают то, что вы намеревались сделать.

(ns shopping-2.core
  (:require-macros [cljs.core.async.macros :refer [go]])
  (:require [cljs.core.async :as async :refer [put! chan <! >! close!]]))

;; put! version
(go
  (let [c (chan)]
    (put! c "hello")
    (.write js/document (<! c))
    (close! c)))


;; Concurrent version
;; 2 *threads* concurrently running. One is the putter and the other is the
;; reader
(let [c (chan)]
  (go
    (.write js/document (<! c))
    (close! c))
  (go
    (>! c "hello")))

В версии параллельных потоков вы увидите, что даже первый код, который запускается первым, является прочитанным, это фактически другая процедура, поэтому код, который работает позже (>!), эффективно запускает разблокировку первой процедуры.

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

Я предлагаю прочитать прохождение кода, игнорируя определенные части clojure (>!! <!! и т.д.), а некоторые из учебники swannodette, которые велики (например, Clojurescript 101 и передача последовательных процессов)