2024 Clojure 状态调查!中分享你的想法。

欢迎!请查看关于页面以了解更多关于该功能的信息。

+4
Clojure CLI
已关闭

Hi Clojure 团队,

在 Liftoff,我们是 Clojure 的大用户(超过400k LOC,涵盖250+个项目)。我们构建了一些工具,可以自动为项目生成基于代码静态分析的 deps.edn 文件。

我们的某些工具和测试代码反复调用 clojure.tools.deps.alpha/resolve-deps。从版本 v0.14.1178 开始,我们注意到以下情况

  • resolve-deps 在每次调用时都会创建一个新的 java.util.concurrent.ExecutorService,但在返回之前并未关闭它(代码)。这导致我们的测试代码创建了20k+个线程。
  • clojure.tools.deps.alpha.util.concurrent/submit-task 将线程绑定推入一个固定大小的线程池,但不将它们弹出(代码)。由于线程被重复使用,调用栈持续增长。

我们内部现在使用了一个修改过的工具版本,该版本在每次调用 resolve-deps 时无条件关闭 ExecutorService,并为每个任务弹出线程绑定。这解决了我们的问题,但我们不知道这是否是正确的解决方案。

Clojure 核心团队如何看待 CLI 工具中的并发?我们是否可以期待 CLI 工具的未来版本会改变这种行为吗?

谢谢!

已关闭,并注明:发布于 Clojure CLI 1.11.1.1347

2 个回答

+2

已选中
 
最佳答案

谢谢!这些问题很重要,tools.deps应该表现得更好。由于众多的tools.deps使用都是在单次使用场景(如CLI)中,所以在这方面通常不太重要,但同意这些问题。

已记录为https://clojure.atlassian.net/browse/TDEPS-227,如果我们收到修补程序,我们将很乐意考虑它们。关于流程请参阅https://clojure.org/dev/dev#_becoming_a_contributor

你好,Alex。感谢你的快速回复。我愿意贡献修补程序,但我不确定如何签署贡献者协议。我的雇主对我的贡献有权利,但我没有权限将我的雇主绑定。我们应该如何进行?
或者你的雇主可以签署,或者很不幸,我们无法接受你的贡献。
0

这是一份提议的修补程序

diff --git a/src/main/clojure/clojure/tools/deps/alpha.clj b/src/main/clojure/clojure/tools/deps/alpha.clj
index ec0561f1..70bef534 100644
--- a/src/main/clojure/clojure/tools/deps/alpha.clj
+++ b/src/main/clojure/clojure/tools/deps/alpha.clj
@@ -489,16 +489,20 @@
   {:arglists '([deps-map args-map])}
   ([deps-map args-map]
    (let [{:keys [extra-deps default-deps override-deps threads trace]} args-map
-         n (or threads concurrent/processors)
-         executor (concurrent/new-executor n)
          deps (merge (:deps deps-map) extra-deps)
-         version-map (-> deps
-                       (canonicalize-deps deps-map)
-                       (expand-deps default-deps override-deps deps-map executor trace)
-                       cut-orphans)
-         lib-map (lib-paths version-map)
-         lib-map' (download-libs executor lib-map deps-map)]
-     (with-meta lib-map' (meta version-map))))
+         n (or threads concurrent/processors)
+         executor (concurrent/new-executor n)]
+     (try
+       (let [version-map (-> deps
+                             (canonicalize-deps deps-map)
+                             (expand-deps default-deps override-deps deps-map executor trace)
+                             cut-orphans)
+             lib-map (lib-paths version-map)
+             lib-map' (download-libs executor lib-map deps-map)]
+         (with-meta lib-map' (meta version-map)))
+       (finally
+         ;; Shutdown executor to avoid creating too many threads.
+         (.shutdownNow executor)))))
   ;; deprecated arity, retained for backwards compatibility
   ([deps-map args-map settings]
    (resolve-deps deps-map (merge args-map settings))))
...