gpt4 book ai didi

picocli - 如何在运行时提高命令性能?

转载 作者:行者123 更新时间:2023-12-04 10:52:31 29 4
gpt4 key购买 nike

我有一个带有使用 picocli 3.9.6 的内部命令行的库。这些命令之一是 log命令,它的工作方式与大多数记录器一样,采用日志级别和消息,以及其他几个选项。它在一些使用该库的应用程序中被多次调用,并且我们注意到,与将其切换为 picocli 相比,作为一次性执行此命令时,性能大幅下降。即使日志级别设置为没有任何有趣的事情发生,也是如此。两个版本的核心代码相同。

因此,我们怀疑 picocli 正在使用反射来处理每个命令实例。我们如何提高性能?我注意到 picocli 4.x 包含一个注释处理器,但让我们的用户使用 Graal 对我们来说是不现实的。由于注释不会跨实例更改,也许它们可以被缓存?
log 的代码命令可以在这里找到:

https://github.com/soartech/jsoar/blob/maven/jsoar-core/src/main/java/org/jsoar/kernel/commands/LogCommand.java

我加了一个 testPerformance单元测试在这里:https://github.com/soartech/jsoar/blob/maven/jsoar-core/src/test/java/org/jsoar/kernel/commands/LogCommandTest.java

在我的机器上运行单元测试会产生大约 3 秒的时间。如果我回去提交 2bc4d39549eeb4ad69fd45e97f9607475e6426d9 (2018 年 10 月 30 日),正好在 log 之前命令被转换为 picocli,并将测试放在那里(你可以用较新的版本替换整个单元测试文件),我得到了大约 0.03 秒的时间。

最佳答案

我使用 Java Flight Recorder 查看执行 LogCommandTest 时的热点是什么,并且我发现,确实,显示在顶部的本质上是 picocli 根据注释构建模型。

仔细一看,当前的应用逻辑重新初始化了一个新的CommandLine带有 Log 新实例的模型每次调用 LogCommand .这是确保每次调用都重置所有值的一种方法,但是当命令被大量调用时,成本会很高。幸运的是,这不是唯一的方法。

我建议您创建 CommandLine对象一次,并将其重用于所有后续调用。 Picocli 旨在以这种方式使用:在解析新的用户输入之前,picocli 会将选项和参数重置为其默认值。

下面的补丁实现了这一点。我专注于LogCommand因为这就是 OP 的内容,但您可能希望对其他频繁调用的性能敏感命令应用类似的更改。

我测试了下面的内容,发现 LogCommandTest.testPerformance在我的机器上测试从 5 秒缩短到 0.5 秒。 LogCommandTest 中的其他测试还是通过。

建议补丁:

Index: jsoar-core/src/main/java/org/jsoar/kernel/commands/LogCommand.java
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
--- jsoar-core/src/main/java/org/jsoar/kernel/commands/LogCommand.java (revision 576ae0a1420177bad69d2f9e2e0d405c74f87ab0)
+++ jsoar-core/src/main/java/org/jsoar/kernel/commands/LogCommand.java (date 1577052510919)
@@ -23,6 +23,7 @@
import org.jsoar.util.commands.SoarCommandContext;
import org.jsoar.util.commands.SoarCommandInterpreter;

+import picocli.CommandLine;
import picocli.CommandLine.Command;
import picocli.CommandLine.HelpCommand;
import picocli.CommandLine.Model.CommandSpec;
@@ -39,17 +40,22 @@
{
private final Agent agent;
private SoarCommandInterpreter interpreter;
+ private Log log;
+ private CommandLine logCommand;

public LogCommand(Agent agent, SoarCommandInterpreter interpreter)
{
this.agent = agent;
this.interpreter = interpreter;
+ this.log = new Log(agent, interpreter, null);
+ this.logCommand = new CommandLine(log);
}

@Override
public String execute(SoarCommandContext context, String[] args) throws SoarException
{
- Utils.parseAndRun(agent, new Log(agent, interpreter, context), args);
+ this.log.context = context;
+ Utils.parseAndRun(agent, logCommand, args);

return "";
}
@@ -57,7 +63,7 @@
@Override
public Object getCommand()
{
- return new Log(agent,interpreter,null);
+ return logCommand;
}

@Command(name="log", description="Adjusts logging settings",
@@ -67,7 +73,7 @@
private final Agent agent;
private final LogManager logManager;
private final SoarCommandInterpreter interpreter;
- private final SoarCommandContext context;
+ private SoarCommandContext context;
private static String sourceLocationSeparator = ".";

@Spec
Index: jsoar-core/src/main/java/org/jsoar/kernel/commands/Utils.java
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
--- jsoar-core/src/main/java/org/jsoar/kernel/commands/Utils.java (revision 576ae0a1420177bad69d2f9e2e0d405c74f87ab0)
+++ jsoar-core/src/main/java/org/jsoar/kernel/commands/Utils.java (date 1577052217242)
@@ -41,10 +41,25 @@

parseAndRun(command, args, ps);
}
-
+
+ /**
+ * Executes the specified command and returns the result.
+ * A command may be a user object or a pre-initialized {@code picocli.CommandLine} object.
+ * For performance-sensitive commands that are invoked often,
+ * it is recommended to pass a pre-initialized CommandLine object instead of the user object.
+ *
+ * @param command the command to execute; this may be a user object or a pre-initialized {@code picocli.CommandLine} object
+ * @param args the command line arguments (the first arg will be removed from this list)
+ * @param ps the PrintStream to print any command output to
+ * @return the command result
+ * @throws SoarException if the user input was invalid or if a runtime exception occurred
+ * while executing the command business logic
+ */
public static List<Object> parseAndRun(Object command, String[] args, PrintStream ps) throws SoarException {

- CommandLine commandLine = new CommandLine(command);
+ CommandLine commandLine = command instanceof CommandLine
+ ? (CommandLine) command
+ : new CommandLine(command);

// The "debug time" command takes a command as a parameter, which can contain options
// In order to inform picocli that the options are part of the command parameter

关于picocli - 如何在运行时提高命令性能?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/59415247/

29 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com