2016-05-06 13 views
0

Я хотел бы запустить код какКак предотвратить близко! -ную, прежде чем ставить-ки в онто-чан

(->> input 
    (partition-all 5) 
    (map a-side-effect) 
    dorun) 

асинхронно разделив вход и выход (а-побочный эффект).

Затем я написал код для эксперимента ниже.

;; using boot-clj 
(set-env! :dependencies '[[org.clojure/core.async "0.2.374"]]) 
(require '[clojure.core.async :as async :refer [<! <!! >! >!!]]) 

(let [input (range 18) 
     c (async/chan 1 (comp (partition-all 5) 
          (map prn)))] 
    (async/onto-chan c input false) 
    (async/close! c)) 

объяснение этого кода:

  • Собственно элементы ввода и его количество не определено перед запуском и элементов на входе может быть принято некоторыми числами от 0 до 10.
  • async/onto-chan используется для помещения Seq элементов (фрагмента ввода) в канал c и будет вызываться много раз, поэтому третий аргумент false.
  • prn является заменой для a-side-effect.

Я ожидал, что приведенный выше код печатает

[0 1 2 3 4] 
[5 6 7 8 9] 
[10 11 12 13 14] 
[15 16 17] 

в РЕПЛ однако он не печатает никаких символов.

А потом я добавить время, чтобы ждать, как этот

(let [c (async/chan 1 (comp (partition-all 5) 
          (map prn)))] 
    (async/onto-chan c (range 18) false) 
    (Thread/sleep 1000) ;wait 
    (async/close! c)) 

Этот код дал мой ожидаемый результат выше.

И затем я проверяю core.async/onto-chan.

И я думаю, что случилось:

  1. канал c был core.async/close! редактор в моем коде.
  2. каждый пункт аргумента core.async/onto-chan был поставлен (core.async/>!) напрасно в go-loop в onto-chan, потому что канал c был закрыт.

Есть ли способ положить предметы до close! ing? написать синхронную версию onto-chan не используя go-loop?

Или моя идея не так? Идея

+1

Вы объясните, что ваша цель? Почему вы создаете chan 'c', ассоциируете с ним преобразователь, но никогда не принимаете никаких значений? – glts

+2

https://clojure.github.io/core.async/#clojure.core.async/onto-chan Функция on-chan возвращает канал, который вы можете подождать, а затем закрыть c. – megakorre

+0

@gits - моя цель слишком сложна, чтобы объяснить здесь. Я только что написал консульскую версию моего производственного кода. Конечно, есть много способов, если только печатать числа. Так же, как вы сказали, chan 'c' не означает никаких значений, но потребляет значения с' prn' сам по себе. – ryo

ответ

1

Ваш второй пример с Thread.sleep только «работает» по ошибке.

Причина это работает, что каждый преобразуется значение результата, который выходит из преобразователя c «s является nil, а так nil s не допускается в каналах, генерируется исключение, и никакого значения не помещаются в c: это что позволяет продюсеру onto-chan продолжать поместить в канал, а не ждать блока.Если вы вставляете второй пример в REPL, вы увидите четыре трассировки стека - по одному для каждого раздела.

nil s, конечно, связано с отображением над prn, что является функцией побочного эффекта, которая возвращает nil для всех входов.

Если я правильно понял ваш дизайн правильно, ваша цель состоит в том, чтобы сделать что-то вроде этого:

(defn go-run! [ch proc] 
    (async/go-loop [] 
    (when-let [value (<! ch)] 
     (proc value) 
     (recur)))) 

(let [input (range 18) 
     c (async/chan 1 (partition-all 5))] 
    (async/onto-chan c input) 
    (<!! (go-run! c prn))) 
  • Вы действительно нужен продюсер и потребитель, иначе ваша программа будет блокировать. Я ввел потребителя go-loop.
  • В общем, map и побочные эффекты не идут хорошо, поэтому я извлек побочный эффект prn в потребитель.
  • onto-chan нельзя назвать «много раз» (по крайней мере, в показанном коде), поэтому ему не нужен аргумент false.
+0

Спасибо, я, наверное, понимаю. Но у меня все еще есть кое-что, что я не могу понять. Какая доза « ryo

+0

Да, помните, что код здесь работает в основном потоке, но все, отправленное на объекты 'go', является асинхронным и работает в потоках daemon, поэтому вы должны включить какой-то способ синхронизации с завершением' go' threads. Здесь ' glts

0

если взять megakorre в:

(let [c (async/chan 1 (comp (partition-all 5) 
          (map prn))) 
     put-ch (async/onto-chan c (range 18) false)] 
    (async/alts!! [put-ch]) 
    (async/close! c)) 
+1

Я все еще смущен проблемой, которую вы пытаетесь решить. Когда я вставляю этот код в свой REPL, я получаю ошибку утверждения: ваш преобразователь отображает символ 'prn', который возвращает' nil' для каждого значения, а 'nil' нельзя вставлять или брать из канала. – glts

+0

@glts - извините за мое плохое объяснение. Я хотел бы запустить '(- >> (диапазон 18) (partition-all 5) (map prn) dorun)' асинхронно. «prn» заменяет побочный эффект, который я действительно хочу сделать. – ryo

+0

Я не заметил, что 'nil' не могут быть введены или взяты из канала. Но в моей среде ошибка адаптации не возникает (clojure 1.7.0 и 1.8.0). Как я уже писал, ассоциатор-преобразователь с chan, возвращающим «nil», все равно плохо. – ryo