簡體   English   中英

core.async 通道 - 跟蹤發生的情況(示例)

[英]core.async channels - tracing what happens when (example)

我在Ch。 Paul Butcher 7 周內7 個並發模型中的 6 個,重點是core.async

我們有以下功能

(defn map-chan [f from]                                                         
  (let [to (chan)]
    (go-loop []
      (when-let [x (<! from)]    
        (>! to (f x))            
        (println "parking channel write.") 
        (recur))                         
      (close! to))
    (println "map-chan done.")
    to)) 

我自己添加了printlns ,以探索計算的確切順序,我想在這里詢問。

我們可以這樣運行

(def ch (to-chan (range 10)))             ; [1]
(def mapped (map-chan (partial * 2) ch))  ; [2]
(<!! (async/into [] mapped))              ; [3]

;; [1] Create & rtn a channel from els of seq, closing it when seq fin.
;; [2] map-chan returns immediately, with blocked go blocks inside of it.
;; [3] calling async/into finally triggers the parked channel writes, as seen below.

在回復中:

channels.core=> (def ch (to-chan (range 10)))
#'channels.core/ch
channels.core=> (def mapped (map-chan (partial * 2) ch))
map-chan done.
#'channels.core/mapped
channels.core=> (<!! (async/into [] mapped))
parking channel write.
parking channel write.
parking channel write.
parking channel write.
parking channel write.
parking channel write.
parking channel write.
parking channel write.
parking channel write.
parking channel write.
[0 2 4 6 8 10 12 14 16 18]
channels.core=> 

我們這里有一個(同步)(即無緩沖)通道,它准備好了寫入器和讀取器。 為什么在調用async/into之前不會觸發上面的“停放通道寫入”? (觸發它的不是使用<!!讀取的通道,它是async/into自身 - 易於檢查)。 我不是在抱怨這個,只是想了解為什么痕跡是這樣的。 頻道實際上是否也很懶惰? 他還沒有在書中提到這一點。

請注意,對這段代碼的依賴是org.clojure/core.async "0.1.267.0-0d7780-alpha" ,如果這有什么不同的話。

此外,在書中,他使用了長度為 10 的緩沖通道。然而,我也嘗試使用無緩沖(同步)通道,結果似乎相同。

您的輸出通道to的大小為零,因此在請求相應的鏡頭之前無法進行寫入。 查看代碼的修改版本:

(ns tst.demo.core
  (:use tupelo.core tupelo.test )
  (:require
    [clojure.core.async :as async]
    ))

(defn map-chan [f from]
  (let [to (async/chan)]
    (async/go
      (loop []
        (when-let [x (async/<! from)]
          (println "put - pre")
          (async/>! to (f x))
          (println "put - post")
          (recur)))
      (async/close! to))
    (println "map-chan returns output buffer")
    to))

(dotest
(println :1)
(spyx
  (def ch (async/to-chan (range 10)))) ; [1]

(Thread/sleep 2000) (println :2)
(spyx
  (def mapped (map-chan (partial * 2) ch))) ; [2]

(Thread/sleep 2000) (println :3)
(spyx
  (async/<!! (async/into [] mapped))) ; [3]
  )

結果:

-------------------------------
   Clojure 1.10.1    Java 13
-------------------------------

lein test tst.demo.core
:1
(def ch (async/to-chan (range 10))) => #'tst.demo.core/ch
:2
map-chan returns output buffer
(def mapped (map-chan (partial * 2) ch)) => #'tst.demo.core/mapped
put - pre
:3
put - post
put - pre
put - post
put - pre
put - post
put - pre
put - post
put - pre
put - post
put - pre
put - post
put - pre
put - post
put - pre
put - post
put - pre
put - post
put - pre
put - post
(async/<!! (async/into [] mapped)) => [0 2 4 6 8 10 12 14 16 18]

因此,go 循環確實立即開始運行,但第一個 put 操作會阻塞,直到步驟 [3] 中的async/into發生。

如果我們使用長度為 20 的緩沖輸出通道,我們會看到在步驟 [3] 發生之前運行的 go 循環:

...
(let [to (async/chan 20)]
   ...

結果:

:1
(def ch (async/to-chan (range 10))) => #'tst.demo.core/ch
:2
map-chan returns output buffer
(def mapped (map-chan (partial * 2) ch)) => #'tst.demo.core/mapped
put - pre
put - post
put - pre
put - post
put - pre
put - post
put - pre
put - post
put - pre
put - post
put - pre
put - post
put - pre
put - post
put - pre
put - post
put - pre
put - post
put - pre
put - post
:3
(async/<!! (async/into [] mapped)) => [0 2 4 6 8 10 12 14 16 18]

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM