2024年Clojure状态调查!分享您的想法。

欢迎!有关这方面的工作方式,请参阅关于页面获取更多信息。

0
tools.cli
重新标记

tools.cli/parse-opts接受参数、选项规范和附加选项。它调用compile-option-specsrequired-arguments来构建specsreq。然后它使用这些规范和要求对提供的args(以及选项)进行验证。对于给定应用程序,前两步在整个调用过程中不会发生变化。

我建议一个名为make-parse-opts-fn的新函数,该函数在前端执行compile-option-specsrequired-arguments操作,并返回一个依赖于编译后的specsreq的函数。它可以这样使用:(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

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

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

我不怀疑您关于预先编译然后多次解析比多次运行整个过程更快这一基准测试的结果——但我不明白这有什么作用。
根据自述文档中的说明,两个用例是“按顺序处理子命令”以及在运行测试。我最初深入这项工作时认为预编译对于支持实时编译的单次运行有帮助,但实际上我不这么认为。然而,这种分割在我运行测试套件时的确略有帮助,在这种情况下,我通过命令行接口多次调用代码。
对于“按顺序处理子命令”,这通常只有在启动时才会执行一次,除非你在编写某种交互式外壳(这可能具有不同的语法,并不适合工具的 cli 接口)。

如果这对您有帮助,我会很乐意将私有函数公开,这样您就可以创建自己的预处理/编译包装器,但这并不感觉这是一个能够直接嵌入 API 的编译用途案例。
的确,它只发生一次,我考虑的是连续处理子命令和多次调用 parse-opts。

我认为使 parse-opts 中调用的私有函数公开会很好,但我不再确信预编译是一个好主意。也许通过执行编译并将结果数据复制粘贴回我的代码中,然后再写一个解析 opts 的第二半部分的功能可以获取一些速度优势?

是的,将编译函数公开(在文档字符串中说明预期隐私)至少可以让我更容易地尝试这个方案。
Noah,由于你可以调用私有函数(使用 '#' 来引用它们的 Vars),你是否可以先行进行那些实验——如果它们显示出有价值的改进,那么我将着手将这些相关部分公开。谢谢。
嗨 Sean!经过大约 9 个月的各种尝试后,我认为唯一需要改变的是我希望 `cli/summarize` 是公开的。我将 `:summary-fn identity` 传递给 `cli/parse-opts`,以避免构建总结字符串,只有当用户请求帮助文档时才调用 `(#'cli/summarize summary)`。如果我能够访问它,即使它是私有的(如所示),但这会产生解引用的成本,这是我希望避免的。
开玩笑的,`cli/summarize` 已经是公开的。我想文档字符串让我误以为它是私有的,我从来没有真正检查过。我希望我能读懂。:哭泣
所以...看来 TCLI-101 可以关闭,无需采取任何行动?
是的,谢谢。

1 个回答

+1

选择了
 
最佳回答
...