请在2024 Clojure 状态调查!中分享您的想法。

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

0
tools.cli
重新打标签

tools.cli/parse-opts 接受参数、选项规范以及额外选项。它调用 compile-option-specsrequired-arguments 以构建 specreq。然后,它使用提供的 args(连同选项)上的这些规范和要求进行验证。对于特定的应用程序,前两步在调用之间不会改变。

我提出一个新函数 make-parse-opts-fn,它在最初执行 compile-option-specsrequired-arguments,并返回依赖于编译后的 specreq 的函数。它可以这样使用:(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编译时单次运行,但我并不认为这是实际情况。然而,当运行我的测试套件时,这略微有所帮助,因为我通过命令行界面大量调用代码。
在“按顺序处理子命令”中,这通常只在启动时执行一次,除非你在编写某种交互式shell(可能有不同的语法,对工具.cli也不是非常友好)。

如果这会有所帮助,我会很高兴将私有函数公开,这样你就可以编写自己的预处理/编译包装器,但这感觉不是一个适合直接嵌入API的编译用例。
这是事实,它只发生一次。我考虑的是连续多次处理子命令并调用parse-opts。

我认为让parse-opts中调用的私有函数公开会很好,但我不再相信预编译是个好主意。也许通过编译然后将其结果复制粘贴回我的代码中,并编写一个使用手动编译的opts的parse-opts的第二半函数,可以从中获得速度上的提升?

是的,使编译函数公开(在文档字符串中注明预期的隐私)至少让我更容易实验这个想法。
诺亚,既然你可以调用私有函数(使用'#'来引用它们的变量),你能否帮忙进行这些实验——如果它们显示出有价值的改进,那么我会继续公开相关部分。谢谢。
嗨Sean!在尝试了大约9个月后,我认为唯一需要改变的是,我希望`cli/summarize`是公开的。我将`:summary-fn identity`传递给`cli/parse-opts`以避免构建摘要字符串,仅在用户请求帮助文档时才调用`(#'cli/summarize summary)`。如果它是私有的(如所示),我可以访问它,但这会产生解引用成本,我希望能避免。
开玩笑的,`cli/summarize`已经是公开的。我认为文档字符串让我认为它是私有的,我从未实际检查过呵呵。我希望我会读书:哭泣
所以……听起来TCLI-101可以关闭,无需采取任何行动?
是的,谢谢。

1 个回答

+1

选择
 
最佳回答
...