2016-05-06 9 views
0

前に入れ-INGのを-ing私は非同期入力と出力( - 副作用)を分割し!上にちゃん

(->> 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に配置するために使用され、何度も呼び出され、3番目の引数はfalseです。
  • prnは、a-side-effectの代替品です。

私は版画REPLで

[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. の各項目はが閉じていたのでgo-looponto-chanに無駄に(core.async/>!)を入れました。

close!の前にアイテムを入れる方法はありますか? go-loopを使用していないonto-chanの同期バージョンを作成しますか?

私の考えは間違っていますか? megakorreのアイデアを取って

+1

あなたの目標は何ですか?あなたはなぜchan 'c'をつくってトランスデューサをそれに関連付けるのですか? – glts

+2

https://clojure.github.io/core.async/#clojure.core.async/onto-chan オンチャーン機能は、待機してから閉じることができるチャンネルを返します。 – megakorre

+0

@gits - 私の目標はここで説明するには複雑すぎる。私はちょうど私の生産コードの合意バージョンを書いた。もちろん、数字を印刷するだけの方法はたくさんあります。ちょうどあなたが言ったように、 'c'はトークンではなく、' prn'で値を消費します。 – ryo

答えて

1

あなたの第二の例は誤って「働きます」。

それが動作する理由は、cのトランスデューサの出てくるすべての変換結果の値がnilで、nil sはチャンネルで許可されていないので、例外がスローされ、そして何の価値がcに入れないことである。これはプロデューサonto-chanはチャネルに入れ続け、待機をブロックしません。2番目の例をREPLに貼り付けると、各パーティションに1つずつ、4つのスタックトレースが表示されます。

nilはもちろん、すべての入力に対してnilを返す副作用関数であるprnにマッピングされているためです。

は私が正しくあなたのデザインを理解していれば、あなたの目標は、このような何かをすることです:

(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'機能にディスパッチされるものはすべて非同期でデーモンスレッドで実行されるため、' go'スレッドの完了と同期する何らかの方法を含める必要があります。ここで、 ' glts

0

Thread.sleep

(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に貼り付けると、アサーションエラーが発生します。あなたのトランスデューサは、各値に対して 'nil'を返す' prn'をマップし、 'nil'はチャンネルに入れられたり、取り出されたりしません。 – glts

+0

@glts - 私の貧弱な説明に申し訳ありません。私は ' - (range 18)(partition-all 5)(map prn)dorun)'を非同期で実行したいと思います。 'prn'は私が実際にやりたい副作用の代用品です。 – ryo

+0

私は、 'nil'はチャンネルに入れられたりチャンネルから取り出されたりすることができないことに気付かなかった。しかし、私の環境(clojure 1.7.0と1.8.0)には集約エラーはありません。とにかく、私はトランスデューサの関連付けを書いているので、おそらく 'nil'を返すようになりました。 – ryo

関連する問題