Ответ 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 и передача последовательных процессов)