如何使用 core.async 实现 Skynet 1m 微基准测试?
How to implement the Skynet 1m microbenchmark with core.async?
为了尝试理解core.async,我尝试实现"Skynet 1 million microbenchmark"没有成功,即:
Creates an actor (goroutine, whatever), which spawns 10 new actors,
each of them spawns 10 more actors, etc. until one million actors are
created on the final level. Then, each of them returns back its
ordinal number (from 0 to 999999), which are summed on the previous
level and sent back upstream, until reaching the root actor. (The
answer should be 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 的事情感到非常困惑(还有懒惰的评估)。
我应该如何解决这个问题,为什么?
关于core.async的功能有some limitations,所以您不能使用map
或for
功能。
您的实施非常接近正确的实施。几点:
go
== 一个进程,所以你只是创建一个进程,而不是 1m
<!!
是在go block外使用
<!
将在 go 块中使用
- 您使用 for 不正确
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)))
为了尝试理解core.async,我尝试实现"Skynet 1 million microbenchmark"没有成功,即:
Creates an actor (goroutine, whatever), which spawns 10 new actors, each of them spawns 10 more actors, etc. until one million actors are created on the final level. Then, each of them returns back its ordinal number (from 0 to 999999), which are summed on the previous level and sent back upstream, until reaching the root actor. (The answer should be 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 的事情感到非常困惑(还有懒惰的评估)。
我应该如何解决这个问题,为什么?
关于core.async的功能有some limitations,所以您不能使用map
或for
功能。
您的实施非常接近正确的实施。几点:
go
== 一个进程,所以你只是创建一个进程,而不是 1m<!!
是在go block外使用<!
将在 go 块中使用- 您使用 for 不正确
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)))