在我的Clojure程序中将map更改为pmap会导致奇怪的异常(ClassCastException)

时间:2013-05-18 16:49:11

标签: map clojure future

据我所知,Clojure中的pmap就像map一样,但它使用期货来平行计算结果。因此,如果map与它们一起使用,它应该“正常”使用函数和序列。 (除非存在阻止它的邪恶副作用,但是在我的程序中,只有从http服务器加载数据并对其进行转换) 在我的情况下,pmap无法按预期工作。为什么会发生这种情况?

此处出现问题(如果我将map更改为pmap): https://github.com/magicgoose/DvachMaster/blob/master/src/dvach/core.clj#L82

(defn thread-list
  "load threads from all pages, trying each page at most `max-trials` times with `retry-inteval`"
  [board]
    (try
      (let [p0 (load-body (board-addr board 0))
            numpages (count (:pages p0))
            other-pages (map                    ; problem here
                          (comp
                            load-body
                            (partial board-addr board))
                          (range 1 numpages))
            all-pages (cons p0 other-pages)
            ]

        (doall
          ((comp (partial reduce concat) (partial map :threads)) all-pages)))
      (catch Throwable e
        (.printStackTrace e))))

我得到的例外:

java.util.concurrent.ExecutionException: java.lang.ClassCastException: java.lang.Long cannot be cast to java.util.concurrent.Future
    at java.util.concurrent.FutureTask$Sync.innerGet(Unknown Source)
    at java.util.concurrent.FutureTask.get(Unknown Source)
    at clojure.core$deref_future.invoke(core.clj:2108)
    at clojure.core$future_call$reify__6267.deref(core.clj:6308)
    at clojure.core$deref.invoke(core.clj:2128)
    at clojure.core$pmap$step__6280$fn__6282.invoke(core.clj:6358)
    at clojure.lang.LazySeq.sval(LazySeq.java:42)
    at clojure.lang.LazySeq.seq(LazySeq.java:60)
    at clojure.lang.RT.seq(RT.java:484)
    at clojure.core$seq.invoke(core.clj:133)
    at clojure.core$map$fn__4207.invoke(core.clj:2479)
    at clojure.lang.LazySeq.sval(LazySeq.java:42)
    at clojure.lang.LazySeq.seq(LazySeq.java:60)
    at clojure.lang.Cons.next(Cons.java:39)
    at clojure.lang.RT.next(RT.java:598)
    at clojure.core$next.invoke(core.clj:64)
    at clojure.core.protocols$fn__6034.invoke(protocols.clj:146)
    at clojure.core.protocols$fn__6005$G__6000__6014.invoke(protocols.clj:19)
    at clojure.core.protocols$seq_reduce.invoke(protocols.clj:27)
    at clojure.core.protocols$fn__6026.invoke(protocols.clj:53)
    at clojure.core.protocols$fn__5979$G__5974__5992.invoke(protocols.clj:13)
    at clojure.core$reduce.invoke(core.clj:6175)
    at clojure.lang.AFn.applyToHelper(AFn.java:163)
    at clojure.lang.AFn.applyTo(AFn.java:151)
    at clojure.core$apply.invoke(core.clj:619)
    at clojure.core$partial$fn__4190.doInvoke(core.clj:2396)
    at clojure.lang.RestFn.invoke(RestFn.java:408)
    at clojure.core$comp$fn__4154.invoke(core.clj:2331)
    at dvach.core$thread_list.invoke(core.clj:91)
    at dvach.core$eval3813.invoke(NO_SOURCE_FILE:2)
    at clojure.lang.Compiler.eval(Compiler.java:6619)
    at clojure.lang.Compiler.eval(Compiler.java:6582)
    at clojure.core$eval.invoke(core.clj:2852)
    at clojure.main$repl$read_eval_print__6588$fn__6591.invoke(main.clj:259)
    at clojure.main$repl$read_eval_print__6588.invoke(main.clj:259)
    at clojure.main$repl$fn__6597.invoke(main.clj:277)
    at clojure.main$repl.doInvoke(main.clj:277)
    at clojure.lang.RestFn.invoke(RestFn.java:1096)
    at clojure.tools.nrepl.middleware.interruptible_eval$evaluate$fn__1023.invoke(interruptible_eval.clj:56)
    at clojure.lang.AFn.applyToHelper(AFn.java:159)
    at clojure.lang.AFn.applyTo(AFn.java:151)
    at clojure.core$apply.invoke(core.clj:617)
    at clojure.core$with_bindings_STAR_.doInvoke(core.clj:1788)
    at clojure.lang.RestFn.invoke(RestFn.java:425)
    at clojure.tools.nrepl.middleware.interruptible_eval$evaluate.invoke(interruptible_eval.clj:41)
    at clojure.tools.nrepl.middleware.interruptible_eval$interruptible_eval$fn__1064$fn__1067.invoke(interruptible_eval.clj:171)
    at clojure.core$comp$fn__4154.invoke(core.clj:2330)
    at clojure.tools.nrepl.middleware.interruptible_eval$run_next$fn__1057.invoke(interruptible_eval.clj:138)
    at clojure.lang.AFn.run(AFn.java:24)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(Unknown Source)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source)
    at java.lang.Thread.run(Unknown Source)
Caused by: java.lang.ClassCastException: java.lang.Long cannot be cast to java.util.concurrent.Future
    at clojure.core$deref_future.invoke(core.clj:2108)
    at clojure.core$deref.invoke(core.clj:2129)
    at dvach.core$load_body.invoke(core.clj:74)
    at clojure.core$comp$fn__4154.invoke(core.clj:2331)
    at clojure.core$pmap$fn__6275$fn__6276.invoke(core.clj:6354)
    at clojure.core$binding_conveyor_fn$fn__4107.invoke(core.clj:1836)
    at clojure.lang.AFn.call(AFn.java:18)
    at java.util.concurrent.FutureTask$Sync.innerRun(Unknown Source)
    at java.util.concurrent.FutureTask.run(Unknown Source)
    ... 3 more

1 个答案:

答案 0 :(得分:2)

堆栈跟踪抱怨的问题是第74行的@max-trials;这应该是max-trials而不是max-trials。 (@retry-count是一个在第66行初始化为try的循环变量;它将是一个数字,然后在每次迭代时递减。)

它可能会间歇性地出现,因为只有在第68行开始的{{1}}块无法获取结果时才会达到代码中的那一点。