clojure - 如何使用 core.async 实现天网 1m 微基准测试?

标签 clojure channel coroutine core.async

为了尝试理解core.async,我尝试实现了“天网100万微基准测试”没有成功,即:

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 的许多事情(以及惰性求值)感到非常困惑。

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

最佳答案

some limitations关于 core.async 能够做什么,所以你不能使用 mapfor职能。

您的实现非常接近正确的实现。几点:

  • go == 一个进程,所以你只是在创建一个进程,而不是 1m
  • <!!用于 go 块之外
  • <!将在 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)))
    

    关于clojure - 如何使用 core.async 实现天网 1m 微基准测试?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/35400990/

    相关文章:

    python - 如何通过gdb获取python eventlet堆栈

    jdbc - 如何使用 clojure.jdbc 查询列表

    Clojure 线程!功能

    android - 将均衡器分配给单个 channel

    select - 戈朗 : select statement exits when it shouldn't

    android - 当被另一个对象(如 TextWatcher)封装时,参与者或 channel 是否需要被管理(关闭/终止)?

    clojure - 使用集合时的 ​​core.logic stackoverflow

    scala - 为什么向量这么浅?

    go - 解释: Don't communicate by sharing memory; share memory by communicating

    firebase - Unity3d 与 Firebase : Can't Start Coroutine