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

欢迎!请访问关于页面了解有关本站更多详细信息。

0投票
tools.cli
修改标签

tools.cli/parse-opts接受参数、选项规范和附加选项。它调用compile-option-specsrequired-arguments来构建规格req。然后它使用这些规格和req对提供的args(连同选项)执行验证。对于一个给定的应用程序,前两步在调用间不会改变。

我提议一个新的make-parse-opts-fn函数,它预先执行compile-option-specsrequired-arguments并返回一个依赖于编译后的规格req的函数。它可以像这样使用:(def compiled-parser (make-parse-opts-fn cli-options))

使用criterium进行的微基准测试表明,速度提高了不止一倍(首先是tools.cli/parse-opts,其次是预编译的解析器)

; user=> (def cli-options
  [["-h" "--help" "This message"]
   [nil "--extra" "Output in extra format"
    :default false]
   ["-q" "--quiet" "Print no suggestions, only return exit code"
    :default false]])
#'user/cli-options

; user=> (bench (cli/parse-opts ["--quiet" "src"] cli-options :in-order true))
Evaluation count : 10962 in 6 samples of 1827 calls.
             Execution time mean : 65.021329 µs
    Execution time std-deviation : 5.276033 µs
   Execution time lower quantile : 58.658638 µs ( 2.5%)
   Execution time upper quantile : 69.724228 µs (97.5%)
                   Overhead used : 9.607933 ns
nil

; user=> (bench (compiled-parser ["--quiet" "src"] :in-order true))
Evaluation count : 24660 in 6 samples of 4110 calls.
             Execution time mean : 25.090846 µs
    Execution time std-deviation : 253.361821 ns
   Execution time lower quantile : 24.769079 µs ( 2.5%)
   Execution time upper quantile : 25.413286 µs (97.5%)
                   Overhead used : 9.607933 ns
nil

如果将附加选项也提升到make-parse-opts-fn中(以速度换取灵活性),则差异更加明显,比现有的tools.cli/parse-opts函数提供了大约10倍的速度提升

; user=> (bench (compiled-parser-2 ["--quiet" "src"]))
Evaluation count : 73116 in 6 samples of 12186 calls.
             Execution time mean : 8.349923 µs
    Execution time std-deviation : 51.419864 ns
   Execution time lower quantile : 8.282266 µs ( 2.5%)
   Execution time upper quantile : 8.407998 µs (97.5%)
                   Overhead used : 9.607933 ns

Found 2 outliers in 6 samples (33.3333 %)
	low-severe	 1 (16.6667 %)
	low-mild	 1 (16.6667 %)
 Variance from outliers : 13.8889 % Variance is moderately inflated by outliers
nil

如果有兴趣,我可以提供补丁。

你能解释在应用程序的单次运行中多次解析命令行参数的使用场景吗?

我不怀疑你的基准测试显示预先编译然后再多次解析比多次运行整个过程更快,但我不明白为什么会这样有用。
两个使用案例是“按顺序处理子命令”,如readme中所述,以及运行测试。我最初在这个假设下深入研究,即预编译有助于AOT编译时的单次运行,但我认为这实际上并不正确。然而,这种分割在运行我的测试套件时微有帮助,我在其中多次通过CLI接口调用代码。
“按顺序处理子命令”仍然是在启动时通常只会执行一次的操作,除非你正在编写某种交互式外壳(这可能有不同的语法,工具.cli也不太容易适应)。

如果这能帮到的话,我很乐意将私有函数公开,这样你就可以编写自己的包装器来处理预处理/编译,但这感觉不是一个足够编译以至于可以直接将其嵌入API的使用案例。
这确实是只发生一次,我正在考虑连续多次处理子命令并调用parse-opts。

我认为将parse-opts中调用的私有函数公开化会不错,但我不太确信预编译是个好主意。也许通过执行编译然后将结果数据复制粘贴回我的代码中,编写一个使用手动编译的opts的parse-opts的第二部分函数,可以提高速度?

是的,将编译函数公开(在文档字符串中注明预期隐私),至少可以让我更容易地实验。
诺亚,既然你可以调用私有函数(使用 '#' 来引用它们的变量),麻烦你亲自做一下这些实验——如果它们显示出值得改进的地方,那么我将继续将相关部分公开。谢谢。
嗨,肖恩!经过大约9个月的各种尝试,我认为唯一需要改变的是,我想将 `cli/summarize` 设置为公开。我向 `cli/parse-opts` 传递 `:summary-fn identity` 来避免构建总结字符串,只有在用户请求帮助文档时才调用 `(#'cli/summarize summary)`。如果它是私有的,我可以访问它(如所示),但这会有解引用的成本,而我希望避免。
开玩笑的,`cli/summarize` 已经是公开的。我想文档字符串让我误以为它是私有的,我实际上从未检查过。我希望我能学会阅读。:泣
所以……听起来 TCLI-101 可以关闭,不需要采取任何行动了?
是的,谢谢。

1 答案

+1

选择了
 
最佳答案
...