如何使用core.async实现Skynet 1m微基准测试?

时间:2016-02-15 03:20:34

标签: clojure channel coroutine core.async

为了尝试理解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(以及懒惰评估)的事情感到困惑。

我该如何解决这个问题?为什么?

1 个答案:

答案 0 :(得分:7)

core.async可以执行some limitations,因此您无法使用mapfor函数。

您的实施与正确的实施非常接近。一些要点:

  1. go ==一个流程,因此您只需创建一个流程,而不是1米
  2. <!!将在go block
  3. 之外使用
  4. <!将在go blocks
  5. 中使用
  6. 您错误地使用for
  7. doall只接受一个参数
  8. 可能可以改进的工作实现:

    (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)))