首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >ProcessBuilder挂起

ProcessBuilder挂起
EN

Stack Overflow用户
提问于 2020-03-27 19:50:55
回答 1查看 807关注 0票数 0

我使用以下代码运行命令:

代码语言:javascript
运行
复制
open class AppRunner {

    fun run(
        app: String,
        args: Array<String>,
        timeoutAmount: Long = 6000,
        timeoutUnit: TimeUnit = TimeUnit.SECONDS
    ): AppResult {

        val command = mutableListOf(app)
            .apply {
                addAll(args)
            }

        val commandString = command.joinToString(" ") { "\"$it\"" }
        Kimber.d("Executing command: $commandString")

        val processResult = ProcessBuilder(command)
            .redirectOutput(ProcessBuilder.Redirect.PIPE)
            .redirectError(ProcessBuilder.Redirect.PIPE)
            .start()
            .apply {
                waitFor(timeoutAmount, timeoutUnit)
            }

        val exitCode = processResult.exitValue()
        val stdOut = processResult.inputStream.bufferedReader().readText()
        val stdErr = processResult.errorStream.bufferedReader().readText()

        return AppResult(exitCode, stdOut, stdErr)
    }

    data class AppResult(
        val exitCode: Int,
        val stdOut: String,
        val stdErr: String
    ) {

        fun isSuccessful(): Boolean = exitCode == 0

        fun getStdOutLines(): List<String> = stdOut.split("\n")
        fun getStdErrLines(): List<String> = stdOut.split("\n")

    }

}

就像这样:

代码语言:javascript
运行
复制
val args = arrayOf(
                audioFile.absolutePath,
                "-r",
                getRecognizer(language),
                "-f",
                "json",
                "-q"
        )

        val result = appRunner.run(rhubarbBinary.absolutePath, args)

对于一些像ffmpeg这样的程序,它是有效的,但是上面的例子不起作用。

Raw命令是"/Users/user/<path>/rhubarb" "/var/folders/g6/bmyctvjn7fl3m8kdr0cs1hk80000gn/T/lipsync_audio_14979831388784829375.wav" "-r" "phonetic" "-f" "json" "-q",如果我手动运行它,它可以正常工作。

但是如果我用上面的代码运行它,它就不会启动和冻结。

我确信它没有启动,因为这个命令需要大约30秒才能完成,并且在运行时消耗100%的CPU,而在使用这段代码运行它时,它根本不加载CPU。

我在JVM 8上使用Kotlin 1.3.71,macOS 10.15.4。

怎么了?

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2020-03-27 20:08:14

在读取管道输出之前,您等待程序结束,但是管道只有一个有限的缓冲区,因此当缓冲区已满时,程序将等待您使用缓冲输出,但您正在等待程序结束。死锁!

始终在调用waitFor()之前使用输出。

更新

建议您按以下方式更改代码:

代码语言:javascript
运行
复制
val process = ProcessBuilder(command)
    .redirectErrorStream(true)
    .start()
val stdOut = processResult.inputStream.bufferedReader().readText()
if (process.waitFor(timeoutAmount, timeoutUnit)) {
    val exitCode = processResult.exitValue()
    return AppResult(exitCode, stdOut, "")
}
// timeout: decide what to do here, since command hasn't terminated yet

没有必要指定Redirect.PIPE,因为这是默认的。如果不像这里所示的那样加入stderr和stdout,那么就需要创建线程来单独使用它们,因为它们都有缓冲区的完整问题,所以不能先读取其中的一个线程。

票数 4
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/60893219

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档