C++: 重复调用system()函数

3

我需要关于从C++代码中调用外部程序的帮助。

我必须经常调用JDK包中的javap.exe(可能超过100次),但是使用system("javap.exe some_parameters")非常缓慢。 对于一组参数,它可以很好地工作,但是使用system()进行重复调用是不可接受的。 我认为这仅仅是因为访问硬盘和应用程序运行的成本(但我不确定)。

有什么方法可以提高性能吗? 我可以“将javap.exe保存在RAM中”,并直接调用它吗? 或者,有人知道如何在没有javap.exe的情况下获取Java类描述和方法签名吗?


2
有没有可能拥有一个持久的Java实例,并通过JNI调用/回调进行通信?(这肯定可以通过这种方式完成,问题是是否对您可接受,或者您每次都需要完全不同的Java实例。) - DevSolar
谢谢,我会尝试的。我只是没有太多的Java经验。 - Dmitry
2个回答

6

Java虚拟机启动不便宜,很可能其初始化占用了大部分时间。幸运的是,javap的功能可以直接通过Java代码使用。我建议您编写一个小型Java应用程序,类似于javap,但只需要一次调用即可完成您原本需要成千上万次才能完成的任务。(尽管...也许您已经可以只使用一次?毕竟,javap可以处理多个类文件...)


-1

调用system()很容易,但非常低效,主要是因为你不仅仅启动了指定的程序。相反,你启动了一个进程(一个shell),这个shell将检查你的参数并启动第二个进程。

如果你在支持fork()exec*()的系统上,使用它们可以提高性能。作为伪代码示例,考虑以下内容:

void replace_system(const char *command)
{
    pid_t child = fork();
    if (child < 0) {
        perror("fork:");
        return;
    }

    if (child) {
        /* this is the parent, wait for the child to finish */
        while (waitpid(child, &status, options) <= 0);
        return;
    }

    /* this is the new process */
    exec*(...);
    perror("failed to start the child");
    exit(-1);
}

根据您想要如何排列参数,选择exec*函数之一。您需要将参数字符串分解为组件,并可能提供您喜欢的环境。一旦调用exec*函数,该函数将永远不会返回(除非启动了为其定义的命令时出现错误)。

除了性能考虑之外,使用此功能的另一个原因是,如果需要,它允许您修改子进程的标准路径。例如,您可能对子进程的输出感兴趣;如果您将其stdout修改为可供您使用的管道,则可以简单地读取其打印内容。查找标准的popen()调用的源代码,以找到此示例。


虽然同意 fork/execsystem 更有效率,但与所有 JVM 设置相比,我怀疑通过 shell 的开销只是总运行时间中的小块。 - Sneftel
@Sneftel 我同意(并已点赞您的答案)。尽管在信噪比中,JVM启动时间是system()噪声的信号,但OP表示他可能调用system()超过100次;这会放大很多噪声。 - mah
如果 expensive = 1000 * (large + small),则忽略 small。只有在 large 存在时,对 small 进行任何优化都为时过早。如果 expensive = large + huge*(small),则小的优化可能不为时过早。在上述情况下,你告诉 OP 在 OP 完全忽略 small 的问题(即 small 的优化)时去优化 small 是错误的。任何在 large 存在时对 small 的努力都是浪费的(假设 large 比 small 大得多)。 - Yakk - Adam Nevraumont
@Yakk,根据我猜测的你的反对意见(以及你的否决),你认为不应该提出这样的建议...明白了!然而,我必须尊重地表示不同意;在我看来,存在一个解决方案(大规模)并不意味着(小规模)应该永远被忽视。 - mah

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接