我有一个奇怪的问题,我发现运行并发 shell 命令以提取文件的 Kotlin 代码性能非常差。但是,当使用 Java 代码运行相同的 shell 命令时,性能符合预期。
差异非常显着,Java 代码运行时间为 10-20 秒,而 Kotlin 代码运行时间约为 13 分钟。
特定用例是一个产生 15 个线程的函数,所有线程都调用此提取函数来解压相同的 tar.gz 文件。调用Kotlin函数时,性能较差;当它是Java时,性能如预期。
我反编译为 Java 的 Kotlin 代码与性能良好的 Java 代码几乎相同,唯一的区别是添加了 Kotlin Intrinsics,这应该不会影响性能。
科特林代码:
@Synchronized
@Throws(IOException::class)
fun extractTar(tarFile: Path, extractPath: Path) {
logger.info("Extracting file: " + tarFile.toString())
logger.info("Destination path: " + extractPath.toString())
val start = System.currentTimeMillis()
val untarCommand = Arrays.asList("tar", "-xzf", tarFile.toString(), "-C", extractPath.toString())
val untarProcess = ProcessBuilder()
.command(untarCommand)
.redirectErrorStream(true)
.start()
waitAndCheckProcessOutput(untarProcess, "tar -xzf ${tarFile.toString()} -C ${extractPath.toString()}", 15)
logger.info("Running chmod on folder:" + extractPath.toString())
val chmodCommand = Arrays.asList("chmod", "-R", "0777", extractPath.toString())
val chmodProcess = ProcessBuilder()
.command(chmodCommand)
.redirectErrorStream(true)
.start()
waitAndCheckProcessOutput(chmodProcess, "chmod -R 0777 ${extractPath.toString()}", 15)
logger.info("Extracted in " + printTime(System.currentTimeMillis() - start))
}
它是这样调用的:
IntStream.range(0, count).parallel().forEach{ unsynchronizedMethod() }
在此 unsynchronizedMethod 中调用 extractTar 的地方。
我 95% 确定在 Intrinsic 库调用中不会发生减速,因为检查的值都不应该为空。
还有趣的是,对于少量线程,例如2个线程不会发生减速。随着线程数的增加,性能下降,这让我怀疑这实际上是并发问题。
我还尝试运行 Kotlin-decompiled-to-Java 代码,去除 Intrinsic 库调用,并且该代码具有与本机 Java 代码相同的性能。
慕容森
相关分类