请在 2024 年 Clojure 州调查! 中分享您的想法。

欢迎!请参阅 关于 页面以了解有关本网站如何工作的更多信息。

0
REPL

你好!

我阅读了有关 减少开发期间 repl 启动时间 的内容,并尝试将此知识应用于使用 Leiningen (文章中 Alex 使用 deps.edn 展示了此实践) 启动 REPL。

我的步骤

我覆盖了 clojure.core/load 变量,以跟踪加载模块所用的时间

(alter-var-root #'clojure.core/load (fn [origin-fn]
                                  (if (get (meta origin-fn) ::track-load?)
                                    origin-fn
                                    (vary-meta (fn [& args]
                                                 (let [start# (System/nanoTime)
                                                       ret# (apply origin-fn args)
                                                       elapsed-ms# (/ (double (- (System/nanoTime) start#)) 1000000.0)]
                                                   (newline)
                                                   (pr {:args (vec args)
                                                        :ms   elapsed-ms#})
                                                   (newline)
                                                   ret#))
                                               merge
                                               {::track-load? true}))))

我注意到,加载核心 Clojure 部件花费时间约为 ~0.10-0.20 ms,而加载第三方库模块(例如 cheshire)则花费 ~200-400ms。

正如我理解的那样,减少 REPL 启动时间的主要思想是优先考虑已编译的类而不是 clj 模块(如果 clj 模块未更改)。因此,我们可以编译第三方库并从其已编译的类中获益,而不是解析它们的 clj 文件。

我使用 Leiningen 启动器 jar 编译了所有 Clojure 文件(我的和库),并将编译过的类文件文件夹添加到 :checkout-deps-shares 中,我想这是将包含类文件的文件夹添加到类路径的途径

:checkout-deps-shares [:source-paths :test-paths
                     ~(fn [p] (str (:root p) "/target/uberjar/classes/*"))]

然后我重新启动了 repl,覆盖了 clojure.core/load 来跟踪模块的加载时间,并作为实验执行以下操作

(time (require 'runtime.account :reload-all))

运行时.account 是我的根模块之一。

作为结果,我没有看到第三方库模块的加载时间有差别 :/。

也许你可以给我一些关于决定加载类文件或 clj 文件机制的详细信息,以及监视该活动的方法?

谢谢!

1 个回答

+1

lein uberjar 未必会空运编译所有内容。一种确保方法是将:aot 键设置为:all
你能发布你的lein项目.clj文件吗?

好的!
我收到了,用编译了:aot :all的uberjar运行我的实验。

没有预期的结果 :/


以下是我的project.clj,抱歉格式可能不对

(defproject myproject "1.0.0"
            :dependencies [(comment "deps")]
            :uberjar-name "my-project.jar"
            :main runtime.run
            :source-paths ["src-clj"]
            :resource-paths ["resources"]
            :test-paths ["test-clj"]
            :target-path "target/%s"
            :env {(comment "ENV VARS")}
            :eftest {:multithread?  :namespaces
                           :capture-output? true
                           :test-warn-time  1000}
            :profiles {:default   [:base :system :user :provided :local-dev]
                              :user      {:dependencies         [(comment "dev deps")]
            :checkout-deps-shares [:source-paths :test-paths
                              ~(fn [p] (str (:root p) "/target/uberjar/classes/*"))]}
                       :local-dev {}
                       :uberjar   {:aot      :all
                                          :jvm-opts ["-Dclojure.compiler.direct-linking=true" "-Dclojure.compiler.elide-meta=[:doc :file :line :added]"]}}
            :aliases {"run-tests"  ["trampoline" "run" "-m" "test.core"]
                            "run-server" ["trampoline" "run" "-m" "runtime.run"]}
            :jvm-opts [(comment "JVM OPTS")]
            :repl-options {:timeout 180000
                                      :init-ns runtime.repl})
我发现将 "target/uberjar/classes" 添加到 :src-path 可以将 repl 启动时间从 25 秒缩短到 15 秒。

但是之后
(time (require 'runtime.account :reload-all))

(clojure.tools.namespace.repl/refresh) 无法解析依赖

clojure.tools.namespace.repl 被配置为跟踪以下目录: "src-clj", "test-clj"
我为 lein 项目添加了 :compile 配置文件,并配置了 :aot :all 选项
现在使用 'lein with-profile compile compile',我可以在 "/Users/user-name/core/project-name/target/default/classes" 文件夹中为每个命名空间生成类文件
.

我通过 (clojure.java.classpath/classpath-directories) 检查发现类路径包含此文件夹

lein repl 启动时间为 15 秒,而不是 25 秒

但是使用 (clojure.tools.namespace.repl/refresh) 时会失败,无法解析依赖,文件找不到

我猜这与类加载器有关

正在调查中
...