Clojure期货神秘地死去

时间:2018-01-18 18:29:32

标签: multithreading clojure

我有一个应用程序,它会旋转一些未来来完成长时间的工作。它间歇性地失败了,我试图找出原因。

症状是代码停止执行,并在随机停止。我的未来创造代码是这样的:

(def future-timeout
 ; 1 hour
 3600000)

(def concurrency 200)


(defn do-parallel
  [f coll]
  (let [chunks (partition-all concurrency coll)]
    (doseq [chunk chunks]
      (let [futures (doall
                      (map #(future
                              (try
                                (f %)
                              (catch Exception e
                                (log/error "Unhandled error in do-parallel:" (.getMessage e))
                                :exception)))
                           chunk))
            results (doall (map #(deref % future-timeout :timeout) futures))
            all-ok (every? true? results)]

      (when all-ok
        (log/info "Chunk successful."))

      (when-not all-ok
        (log/error "Chunk unsuccessful.")
        (log/warn "Parallel execution results:" results))

      (swap! chunk-count inc)))
  (log/info "Finished batch")))

并发变量控制批量的大小,因此控制它尝试的并发执行的数量。 f成功返回true。如果超时或例外,他​​们会返回:timeout:exception

我这样做而不是pmap,因为我想控制并发,f是一个长期运行(约10分钟)的网络密集型任务。 pmap似乎是针对中等规模的小批量调整的。

通常情况下这很好。但几个小时后它停止了:

  • 在执行f期间,该功能停止运行。
  • 没有抓住任何例外。没有超时。
  • do-parallel中的循环停止,不再显示日志条目。
  • 其他线程,例如Kafka客户端,继续运行。

可能导致此问题的任何想法?或者采取措施帮助诊断?

3 个答案:

答案 0 :(得分:1)

您可能想尝试安装未捕获的异常处理程序,以查看Executor本身的异常异常是否导致工作停止。

https://github.com/pyr/uncaught有一个设施,但直接从代码直接做。

答案 1 :(得分:0)

Claypool对于控制并行性非常有用。

(cp/pmap (count chunk) f chunk)

将创建一个与块相同大小的临时线程池,并且并行执行所有函数。

这只是表达并行性的建议,而不是你的问题的答案,这是关于错误处理的;我也很好奇!

答案 2 :(得分:0)

也许尝试捕捉Throwable而不是Exception?我之前遇到过问题,因为它已经因为异常而陷入了异常。

我认为如果期货中有未被捕获的例外情况,它会抓住并死而不会将其进一步抛出,因此设置默认的欺骗行为并不会有所帮助。未经测试 - 但这是我的直觉。

你得到" Chunk不成功"至少在消息结束时的消息?因为如果你不这样做,那真的很奇怪......

查看future的实现 - 它在下面使用了一个cachedthreadpool - 它没有线程限制,所以你可能最好直接使用ExecutorService,或类似{{ 3}},就像其他建议所示。