【问题标题】:Kotlin/Java processBuilder efficiency vs python subprocessesKotlin/Java processBuilder 效率 vs python 子进程
【发布时间】:2021-04-21 07:08:48
【问题描述】:

我在处理 JVM 进程时遇到问题,我正在尝试创建一个程序,该程序需要调用不同的语言程序,每次都更改参数,很多次。

例如,假设我需要在 10 秒内通过我的主程序 (KotlinJvm) 调用 node.js 程序 1000 次。

现在,我正在使用 ProcessBuilder 类来创建一个新进程,这样我就可以将信息返回到我的主进程中,但速度不够快。它甚至很慢:/

我研究了一下,发现了 python 子进程库,并试图在那里实现相同的想法。在 python 3.9 中,我的实现效果很好!速度快

1.所以我在问,python subprocess 和 Jvm Process 有什么区别

2。有没有办法像python一样创建Jvm子进程

据我所知,也可以在 Jvm 中创建子进程,方法是从同一个 ProcessBuilder 调用 .start(),但它仍然很慢。

只是为了确保,如果只调用一次就不会出现问题。 问题是我需要在 10-20 秒内调用这个文件 1000 次

在此处添加一些代码作为示例

Kotlin 示例 - 我测试了一下,waitFor() 函数需要很长时间,这是我的问题

Python 示例

感谢您的帮助:)

编辑: 如果这是相同的,有没有办法优化 JVM 进程的执行?环境有什么变化吗?

【问题讨论】:

    标签: java python kotlin process subprocess


    【解决方案1】:

    Python Popen 函数等价于 Java ProcessBuilder.start() 方法。

    在上面的示例中,您将 Jvm 用于子进程 complete 的时间与 Python 用于子进程 start 的时间进行比较。

    要比较相同的东西,你应该比较:

    JVM

    // Start subprocess
    val processHandle = ProcessBuilder("node", "someFile.js").start()
    // Wait subprocess to terminate
    val returnCode = processHandle.waitFor()
    

    Python

    # Start subprocess
    val processHandle = subprocess.Popen(["node", "someFile.js")
    # Wait subprocess to terminate
    val returnCode = processHandle.wait()
    

    编辑

    我在笔记本电脑上运行了简单的测试,但我没有发现 Kotlin 和 Python 之间的性能有显着差异。我会把它放在这里作为测试依据,即使措施没有“正确”完成(通过 JMH for Kotlin),它也给出了一个想法:

    科特林

    所以,对于 Kotlin,我制作了以下 .kts 脚本:

    import java.lang.ProcessBuilder;
    
    fun main() {
        var started : Long = 0
        var completed : Long = 0
    
        for (i in 0 until 1000) {
            
            val start = System.nanoTime()
    
            val process = ProcessBuilder("ls").start()
            
            started += (System.nanoTime() - start)
            
            process.waitFor()
    
            completed += (System.nanoTime() - start)
        }
    
        println("Average time (ms) to start a process: ${started * 1e-9}")
        println("Average time (ms) to complete a started process: ${completed * 1e-9}")
    }
    

    在 jre 10 上加载 Kotlin REPL 1.4.21 后,我得到以下输出:

    Average time (ms) to start a process: 0.667509729
    Average time (ms) to complete a started process: 5.042644314
    

    Python

    在 Python 3.7.9 上,以下脚本:

    import subprocess
    from time import perf_counter_ns 
    
    started = 0
    completed = 0
    
    for i in range(0, 1000):
    
        start = perf_counter_ns()
    
        process = subprocess.Popen("ls")
    
        started += (perf_counter_ns() - start)
        
        process.wait()
    
        completed += (perf_counter_ns() - start)
    
    print("Average time (ms) to start a process: ", started * 1e-9)
    print("Average time (ms) to complete a process: ", completed * 1e-9)
    

    输出:

    Average time (ms) to start a process:  1.620647841
    Average time (ms) to complete a process:  6.208644367000001
    

    所以,我目前的想法是,一旦执行上下文准备好,这两种方法之间的性能应该不会有太大差距。因此,如果您注意到很大的差异,则问题可能是由于子流程之外的一些代码或初始化引起的。

    此时,需要更多细节(一个最小的可重现示例是最好的)才能找到正确答案。

    【讨论】:

    • 好的,我知道我需要添加等待 python。试过了,python 仍然比 Jvm 快得多。有什么想法吗?
    • 嗯,这真的是个谜……我尝试运行你运行的相同代码。毫无疑问,你的笔记本电脑比我的好:D 我的 python 程序在 9 秒内运行但 kotlin 在 26 秒内运行......我检查了我的 kotlin 版本和 jdk,唯一的区别是我使用 openJdk 的 jdk 15
    • 我得到了和你类似的结果,但程序本身并没有解释这一点。如果我在脚本模式下启动 Kotlin 示例,它需要的时间是 Python 的 2 倍(~ 13 秒对~6 秒)。但是,在预编译时,时间会下降到 ~ 5 秒,类似于 Python。额外的时间不是由程序本身花费的,而是由 Kotlin/Java 需要初始化应用程序上下文(编译、JIT、Gc 等)的大型机器造成的巨大开销。它们在该领域的表现非常差,这就是为什么 JVM 经常用于长期运行的服务,而不是用于短期应用程序。
    • 你给了我一个完美的答案!我唯一不明白的是预编译是什么意思?当我在 IntelliJ 或其他 IDE 中运行 Jvm 程序时,它应该编译它。或者通过预编译你的意思是jar文件?再次感谢您的回答:)
    • 脚本是指使用kotlinc to directly execute source code(.kts 文件):kotlinc -script sourceCode.kts。预编译就像你说的:首先我先编译jar文件中的源代码,然后我只测量jar的执行时间:kotlin -classpath bytecode.jar MyMainClass
    猜你喜欢
    • 2015-07-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-05-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多