gpt4 book ai didi

java - ProcessBuilder 挂起

转载 作者:行者123 更新时间:2023-12-02 08:49:13 28 4
gpt4 key购买 nike

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

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")

}

}

像这样:

val args = arrayOf(
audioFile.absolutePath,
"-r",
getRecognizer(language),
"-f",
"json",
"-q"
)

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

对于一些程序,如 ffmpeg它有效,但上面的示例无效。

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

但是如果我使用上面的代码运行它,它只是不会启动并卡住。

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

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

出了什么问题?

最佳答案

在读取管道输出之前,您需要等待程序结束,但是管道只有有限的缓冲区,因此当缓冲区已满时,程序将等待您消耗缓冲的输出,但您正在等待就到节目结束了。 死锁!

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

<小时/>

更新

建议您更改代码如下:

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,则需要创建线程来单独使用它们,因为它们都存在缓冲区已满问题,因此您不能只先读取其中一个。

关于java - ProcessBuilder 挂起,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/60893219/

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