为了尝试理解core.async,我不成功地试图实现“天网100万微基准”,即:
创建一个演员(goroutine,无论如何),它会产生10个新演员, 他们每个人都会产生10个演员等,直到有一百万演员 在最后一级创建。然后,他们每个人都返回它 序号(从0到999999),它们与前一个相加 级别并向上游发回,直到到达根演员。 (该 答案应该是499999500000)。
这里有许多语言的实现:
https://github.com/atemerev/skynet
这是我完全破碎的尝试:
(defn skynet [chan num size div]
(if (= 1 size)
(>! chan num)
(>! chan (reduce + (let [rc (async/chan)
n (/ size div)]
(doall (for [i [0 div]]
(skynet rc (+ num (* i n)) n div))
(for [i [0 div]] (<! rc))))))))
我试图在REPL的go块内调用它:
(time (go (<!! (skynet (async/chan) 0 1000000 10))))
我可能会对很多关于core.async(以及懒惰评估)的事情感到困惑。
我该如何解决这个问题?为什么?
答案 0 :(得分:7)
core.async可以执行some limitations,因此您无法使用map
或for
函数。
您的实施与正确的实施非常接近。一些要点:
go
==一个流程,因此您只需创建一个流程,而不是1米<!!
将在go block <!
将在go blocks doall
只接受一个参数可能可以改进的工作实现:
(defn skynet [parent num size div]
(go ;; We create a new process each time skynet is called
(if (= 1 size)
(>! parent num)
(let [self (chan)
new-size (/ size div)]
(dotimes [i div] ;; dotimes is more explicit for side effects
(skynet self (+ num (* i new-size)) new-size div))
(loop [i div ;; Manual reduce
t 0]
(if (zero? i)
(>! parent t)
(recur (dec i)
(+ t (<! self)))))))))
并称之为:
(time
(do
(def result (chan))
(def x (skynet result 0 1000000 10))
(<!! result)))