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

欢迎!请访问关于页面以了解更多关于这个网站的信息。

0
tools.cli
重标记

tools.cli/parse-opts接受参数、选项规范和附加选项。它调用compile-option-specsrequired-arguments来构建specsreq。然后它使用这些规范和req在提供的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

如果对此感兴趣,我可以提供一个补丁。

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

我确实相信你的基准测试结果表明先预编译然后多次解析比多次执行整个过程更快,但我不明白为什么这会有用。
正如readme中所述,两种用例是“按顺序处理子命令”和运行测试。我最初在此基础上深入研究,以为预编译可以帮助在AOT编译时进行单次运行,但我不认为这实际上是真的。然而,这种划分在运行我的测试套件时略微有帮助,因为我通过CLI界面大量调用代码。
对于“按顺序处理子命令”,这通常只会在启动时执行一次,除非你正在编写某种交互式shell(可能具有不同的语法,但并不适合cli工具)。

如果这样能帮到您,我很乐意将私有函数变为公开,以便您可以编写自己的预处理/编译包装器。但这这类用例可能编译不过分,因此不应该直接将其集成到API中。
是的,它确实只会发生一次,我在想顺序处理子命令并在一次连续调用中多次调用parse-opts。

我认为将parse-opts中调用的私有函数公开化很好,但我不太确定预编译是个好主意。也许通过将编译结果复制粘贴回我的代码,然后编写一个使用手动编译选项的parse-opts第二部分函数可以获得速度优势?

是的,将编译函数公开(在文档字符串中注明其预期隐私)至少可以使我更容易尝试这个想法。
Noah,既然你可以调用私有函数(使用'#'来引用它们的变量),你是否愿意先进行这些实验 —— 如果它们显示出值得改进之处,那么我将进一步将相关部分公开。谢谢。
嗨Sean!经过大约9个月的尝试,我认为唯一应该改变的是,我希望`cli/summarize`是公开的。我通过传入`:summary-fn identity`到`cli/parse-opts`来避免构建摘要字符串,只在用户请求帮助文档时调用`(#'cli/summarize summary)`。如果它是私有的(如所示),我可以访问它,但这有解引用的成本,我希望避免。
开个玩笑,`cli/summarize`已经是公开的。我认为文档字符串让我以为它是私有的,我从未真正检查过 lol。但愿我能学会阅读。 :哭泣
所以……看起来TCLI-101可以关闭,不需要采取行动?
是的,谢谢。

1 个回答

+1

选择
 
最佳答案
...