英文:
Why can't Clojure's async library handle the Go prime sieve?
问题
尝试在Clojure中使用异步库时,我将Go语言中的素数筛选示例进行了翻译。在REPL中运行时,它成功地打印出了小于227的素数,然后停止了。我按下了Ctrl-C并尝试再次运行它,但它不再打印出任何数字。有没有办法让Clojure处理这个问题,或者说异步库还没有准备好处理这个问题?
以下是翻译好的代码:
;; 从Go语言翻译的并发素数筛选算法
(require '[clojure.core.async :as async :refer [<!! >!! chan go]])
(defn generate
[ch]
"将序列2, 3, 4, ... 发送到通道 'ch'。"
(doseq [i (drop 2 (range))]
(>!! ch i)))
(defn filter-multiples
[in-chan out-chan prime]
"从 'in-chan' 复制值到 'out-chan',并删除 'prime' 的倍数。"
(while true
;; 从 'in-chan' 接收值。
(let [i (<!! in-chan)]
(if (not= 0 (mod i prime))
;; 将 'i' 发送到 'out-chan'。
(>!! out-chan i)))))
(defn main
[]
"素数筛选算法:通过连接 filter-multiples 进程来实现。"
(let [ch (chan)]
(go (generate ch))
(loop [ch ch]
(let [prime (<!! ch)]
(println prime)
(let [ch1 (chan)]
(go (filter-multiples ch ch1 prime))
(recur ch1))))))
希望对你有帮助!
英文:
To try out the async library in Clojure, I translated the prime sieve example from Go. Running in the REPL, it successfully printed out the prime numbers up to 227 and then stopped. I hit Ctrl-C and tried running it again but it wouldn't print out any more numbers. Is there a way to get Clojure to handle this, or is the async library just not ready for it yet?
;; A concurrent prime sieve translated from
;; https://golang.org/doc/play/sieve.go
(require '[clojure.core.async :as async :refer [<!! >!! chan go]])
(defn generate
[ch]
"Sends the sequence 2, 3, 4, ... to channel 'ch'."
(doseq [i (drop 2 (range))]
(>!! ch i)))
(defn filter-multiples
[in-chan out-chan prime]
"Copies the values from 'in-chan' to 'out-chan', removing
multiples of 'prime'."
(while true
;; Receive value from 'in-chan'.
(let [i (<!! in-chan)]
(if (not= 0 (mod i prime))
;; Send 'i' to 'out-chan'.
(>!! out-chan i)))))
(defn main
[]
"The prime sieve: Daisy-chain filter-multiples processes."
(let [ch (chan)]
(go (generate ch))
(loop [ch ch]
(let [prime (<!! ch)]
(println prime)
(let [ch1 (chan)]
(go (filter-multiples ch ch1 prime))
(recur ch1))))))
答案1
得分: 2
go
是一个宏。如果你想在go
块中利用类似goroutine的行为,你必须使用<!
和>!
,并且它们必须对go
宏可见(也就是说,你不能将这些操作提取到单独的函数中)。
这个程序的字面翻译似乎很好地工作,即使在主循环中使用了更大的i
:
(require '[clojure.core.async :refer [<! <!! >! chan go]])
(defn go-generate [ch]
(go (doseq [i (iterate inc 2)]
(>! ch i))))
(defn go-filter [in out prime]
(go (while true
(let [i (<! in)]
(if-not (zero? (rem i prime))
(>! out i))))))
(defn main []
(let [ch (chan)]
(go-generate ch)
(loop [i 10 ch ch]
(if (pos? i)
(let [prime (<!! ch)]
(println prime)
(let [ch1 (chan)]
(go-filter ch ch1 prime)
(recur (dec i) ch1)))))))
英文:
go
is a macro. If you want to take advantage of goroutine-like behaviour in go blocks you must use <!
and >!
, and they must be visible to the go
macro (that is you mustn't extract these operations into separate functions).
This literal translation of the program at https://golang.org/doc/play/sieve.go seems to work fine, also with a larger i
in the main loop:
(require '[clojure.core.async :refer [<! <!! >! chan go]])
(defn go-generate [ch]
(go (doseq [i (iterate inc 2)]
(>! ch i))))
(defn go-filter [in out prime]
(go (while true
(let [i (<! in)]
(if-not (zero? (rem i prime))
(>! out i))))))
(defn main []
(let [ch (chan)]
(go-generate ch)
(loop [i 10 ch ch]
(if (pos? i)
(let [prime (<!! ch)]
(println prime)
(let [ch1 (chan)]
(go-filter ch ch1 prime)
(recur (dec i) ch1)))))))
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论