简体   繁体   English

clojure core.async线程块

[英]clojure core.async thread blocks

I have the following code: 我有以下代码:

(defn -db-producer-factory [order-ids-chan next-chan]
  (thread
    (prn "db starting...")
    (while true
      (do
        (prn "db starting2...")
        ;;
        ;; issue spot!
        ;; it stays blocked here-- the orderid doesnt come off the chan
        ;;
        (let [order-id (<!! order-ids-chan)]
          (prn "db->" order-id)
          (condp = order-id
            :finished (>!! next-chan :finished)
            :>> (supress-w-nextexc
                  (->>
                    ; get denorm'd order
                    (-> (r/-get-order :live order-id)
                        denorm/order->denormalized)
                    ; put in a map to avoid nils
                    (hash-map :data)
                    (>!! next-chan)))))))))

(defn -stats-producer-factory [stats-db-chan next-chan]
  (thread
    (while true
      (do
        (let [msg (<!! stats-db-chan)
              data (:data msg)]
          (when data
            (do
              (prn "stats-> " (-> data :order :order-id))
              (supress-w-nextexc
                (q/stats-order-insert (-> data :order)))
              (supress-w-nextexc
                (q/stats-item-insert (-> data :items)))))
          (>!! next-chan msg))))))

(defn -do-orderids [orderids]
  (let [finished-chan (chan)
        order-ids-chan (chan)
        stats-db-chan (chan)
        db-producer (-db-producer-factory order-ids-chan stats-db-chan)
        stats-producer (-stats-producer-factory stats-db-chan finished-chan)]

    (prn "pre-pub")
    ;; pub ids and finished message
    (map #(>!! order-ids-chan %) (conj orderids :finished))
    ;; wait for finish
    (prn "finished? " (<!! finished-chan))
    ;; allow time for finishing
    ;(Thread/sleep 3000)
    ;; close all chans
    (map close! [finished-chan order-ids-chan stats-db-chan db-producer stats-producer])
    ))

The process is initiated via a call to -do-orderids like (-do-orderids [123]) . 该过程通过调用-do-orderids (-do-orderids [123])

The output of the execution is: 执行的输出是:

"db starting..."
"pre-pub"
"db starting2..."

But then it blocks. 但它阻止了。 Why doesn't it pass the orderid at the "issue spot"? 为什么不在“问题点”通过orderid?

Your program blocks because the db-producer , who's blocked waiting for an order ID, never actually receives an order ID on order-ids-chan . 您的程序会阻塞,因为阻止等待订单ID的db-producer实际上从未在order-ids-chan上收到订单ID。

That is because map is lazy. 那是因为map是懒惰的。 So, in this invocation 所以,在这个调用中

(map #(>!! order-ids-chan %) (conj orderids :finished))

the mapping function is never called and no order ID is ever put onto the channel. 永远不会调用映射函数,也不会将任何订单ID放在通道上。

Clojure rule of thumb: Clojure经验法则:

Never use map for side-effects! 切勿使用map进行副作用! Use run! 使用run! instead. 代替。

I think substituting run! 我想替代run! for map in that line (and on the last line where you call close! on the channel) should fix it. 对于该行中的map (以及在通道上调用close!的最后一行)应该修复它。

Unrelated: all the do forms you used are redundant, you can safely remove them and reduce the level of nesting. 无关:所有do构成您使用的是多余的,你可以安全地删除它们,减少嵌套的水平。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM