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

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

0
tools.cli
重新标记

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

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

使用 criterium 进行的微基准测试表明,速度提高了不止两倍(先解析后预编译的解析器)。

; 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

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

by
你能解释一下为什么需要一个应用程序在单个运行中多次解析命令行参数的用例吗?

我不怀疑你的基准测试表明先预编译然后多次解析比多次运行整个过程要快--但我不知道为什么会这样。
根据README文件中的说明,两个用例是“按顺序处理子命令”和运行测试。我最初深入这个领域,以为预编译可以帮助AOT编译时的单次运行,但我认为实际上并非如此。然而,当运行测试套件时,我在cli接口中连续调用代码,这种分割略微有所帮助。
就“按顺序处理子命令”而言,这通常只会启动一次,除非你编写某种交互式外壳(可能会有不同的语法,random cli工具可能不太适用)。

如果这样做能有所帮助,我很乐意将私有函数公开,这样您就可以为预处理/编译编写自己的包装程序,但这似乎并不是一个编译足够的用例,可以直接将其集成到API中。
是的,它只发生一次,我正在考虑连续多次处理子命令并调用parse-opts。

我认为使parse-opts中调用的私有函数公开会很好,但我不再确信预编译是个好主意。也许通过将编译和将结果数据复制粘贴回我的代码中,以及编写一个使用手动编译opt的parse-opts的第二半的功能,我可以获得一定的速度提升?

是的,将编译函数公开(并在文档字符串中注明其隐私目的)将至少使我可以更容易地对这个功能进行实验。
诺亚,由于您可以使用 '#' 引用其变量来调用私有函数,您能否提前进行那些实验?如果它们显示出值得改进的地方,那么我会继续将相关部分公开。谢谢。
by
嗨,肖恩!经过大约9个月的尝试,我觉得唯一需要改变的是,我希望 `cli/summarize` 为公开。我通过传递 `:summary-fn identity` 给 `cli/parse-opts` 来避免构建摘要字符串,只有在用户请求帮助文档时才调用 `(#'cli/summarize summary)`。如果它是私有的(如所示),我可以访问它,但这有解引用成本,我希望避免。
by
开玩笑的,`cli/summarize` 已经是公开的。我认为文档字符串让我误以为它是私有的,我从未实际检查过。我希望我知道如何阅读。:哭泣
by
那么... TCLI-101 是否可以不用采取任何行动就能关闭了吗?
by
是的,谢谢。

1 个答案

+1
by
已选择 by
 
最佳答案
...