Clojure 应用程序启动性能
我在 Clojure 中编写了一些小型实用程序应用程序,我使用 Maven 和 maven-shade-plugin 将它们编译成独立的可执行 JAR 文件(“uberjars”)。这些 uberjar 包含 clojure.jar 的解压版本以及应用程序依赖的其他库(即:commons-cli)。它们很方便,因为我可以将它们发送给客户,而不要求客户安装 Clojure(所有客户都已经安装了 JRE)。
我发现 Clojure 应用程序需要几秒钟的时间才能启动,而用 Java 编写的类似应用程序在同一台计算机上启动只需不到几秒(例如,显示使用消息的时间)。
我怀疑这是因为 Clojure 正在即时编译 clojure.core 库中的一些代码,因为 clojure.jar 文件中有源代码(.clj
文件)。
有什么办法可以预编译这个源代码吗?可以采取其他措施来加快启动性能吗?我听到客户抱怨启动需要多长时间(而且他们不知道也不关心应用程序是用 Clojure、Java 或 Foobar 编写的)。
I have written a few small utility applications in Clojure that I compile into self-contained executable JAR files ("uberjars") using Maven and the maven-shade-plugin. These uberjars contain unpacked versions of clojure.jar and other libraries (i.e.: commons-cli) that the application depends on. They are convenient because I can send them to a customer without requiring that the customer install Clojure (all customers already have the JRE installed).
I have found that the Clojure applications take several seconds to start up, whereas similar applications written in Java start in sub-seconds on the same machines (time to show a usage message, for example).
I suspect that it is because Clojure is on-the-fly compiling some of the code in the clojure.core library as there is source code (.clj
files) in the clojure.jar file.
Is there any way to precompile this source code? Can anything else be done to speed up startup performance? I have heard complaints from the customers about how long the startup takes (and they don't know or care that the application is written in Clojure or Java or Foobar).
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
JVM(至少是 Oracle 的 HotSpot)在减少启动时间方面做了非常棘手的事情。它不会将所有程序的类和方法加载到内存中,而是仅加载当前需要的资源。不需要太多代码来显示使用消息或类似内容,因此实际上只加载了很少的函数,并且 Java 程序可以快速启动。此外,HotSpot 甚至不编译这几个函数 - 它使用 JIT 编译(和其他优化)来重复执行代码。没有理由花时间编译只执行一次的函数,例如几乎所有的启动方法,而 HotSpot 则不会。
那么,Clojure 呢?我认为您不想重写 Clojure 的核心来添加类似的功能。不过,您可以在 Clojure 代码中使用相同的方法。您说您的实用程序使用多个库,这可能会减慢启动速度。因此,请尽可能延迟加载库。例如,您可以从命名空间定义中排除
:use
选项,并在主体函数中调用显式use
。这不会减少总时间,但会将延迟转移到不太明显的时刻。您甚至可以用 Java 编写程序的一小部分,并仅在实际需要时调用 Clojure 代码。JVM (at least Oracle's HotSpot) makes very tricky thing to reduce startup time. It doesn't load to memory all program's classes and methods, it loads only resources it needs right now. There are not so many code needed to show a usage message or something like that, so only few functions are actually loaded and Java program gets started quickly. Moreover, HotSpot doesn't even compile these few functions - it uses JIT compilation (and other optimization) for the code, which is executed repeatedly. There's no reason to spend time to compile functions that will be executed only once, e.g. almost all startup methods, and HotSpot doesn't.
So, what about Clojure? I don't think you would like to rewrite Clojure's core to add similar functionality. Nevertheless, you can use same approach inside of your Clojure code. You said your utilities use several libraries, that can slow down startup. So, load libraries lazily as much as you can. For example, you can exclude
:use
option from your namespace definition and call explicituse
in your principal functions instead. This won't reduce total time, but it will shift dalay to the moment, when it isn't so appreciable. You can even write small part of your program in Java and call Clojure code only when it is actually needed.Clojure 网站上有一个关于 AOT 编译 的精彩描述。这已经减少了一些启动时间。
编辑:已经做出了一些努力来在持久性 JVM 上运行 Clojure 程序,从而减少启动时间。查找jark + jvm。然而该网站似乎已经消失了:(
On the Clojure site there is a nice description of AOT compilation. This will already shave off some startup time.
Edit: there have been some efforts to run Clojure programs on a persistent JVM, thus reducing the start-up time. Look-up jark + jvm. However the site seem to have disapeared :(
当然,还有 java -client JVM 参数用于提高 JVM 启动性能。这个SO问题详细介绍了有关此主题的一些细节。
Of course, there is also the java -client JVM argument for improving JVM start up performance. This SO question goes into some detail about this topic.