मुझे एक अजीब समस्या है जिसमें मुझे एक फ़ाइल निकालने के लिए समवर्ती शेल कमांड चलाने वाले कोटलिन कोड से बहुत खराब प्रदर्शन दिखाई दे रहा है। हालाँकि, जावा कोड का उपयोग करते हुए समान शेल कमांड चलाते समय, प्रदर्शन अपेक्षा के अनुरूप होता है।

अंतर बहुत महत्वपूर्ण है, जावा कोड 10-20 सेकंड में चल रहा है, और कोटलिन कोड लगभग 13 मिनट में चल रहा है।

विशेष उपयोग का मामला एक ऐसा फ़ंक्शन है जो 15 थ्रेड्स को जन्म देता है, जो सभी इस एक्सट्रैक्ट फ़ंक्शन को समान tar.gz फ़ाइल को अनपैक करने के लिए कहते हैं। जब कोटलिन फ़ंक्शन को कॉल किया जाता है, तो प्रदर्शन खराब होता है; जब यह जावा है, तो प्रदर्शन अपेक्षित है।

कोटलिन कोड जिसे मैंने जावा में डीकंपाइल किया है, जावा कोड के लगभग समान है जो कि प्रदर्शनकारी है, केवल अंतर कोटलिन इंट्रिनिक्स के अतिरिक्त है, जो प्रदर्शन को प्रभावित नहीं करना चाहिए।

कोटलिन कोड:

@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))
}

fun waitAndCheckProcessOutput(process: Process, command: String, timeoutInMinutes: Long) {
    try {
        val finished = process.waitFor(timeoutInMinutes, TimeUnit.MINUTES)
        if (!finished) {
            logger.info("Timed out running command $command")
        }
        val output = BufferedReader(InputStreamReader(process.inputStream))
                .lines()
                .collect(Collectors.joining())
        val exitCode = process.exitValue()
        if (exitCode != 0) {
            logger.info("Got exit code " + exitCode + " running command " + command
                    + "\nGot output:\n" + output)
        }
    } catch (e: InterruptedException) {
        logger.info("Interrupted running command $command" + e)
    }
}

fun printTime(timeInMillis: Long): String {
    var duration = Duration.ofMillis(timeInMillis)
    val minutes = duration.toMinutes()
    duration = duration.minusMinutes(minutes)
    val seconds = duration.seconds
    duration = duration.minusSeconds(seconds)
    val millis = duration.toMillis()
    return minutes.toString() + "m " + seconds + "." + millis + "s"
}

कोटलिन कोड जावा में विघटित हो गया:

public final synchronized void extractTar(@NotNull Path tarFile, @NotNull Path extractPath) throws IOException {
  Intrinsics.checkParameterIsNotNull(tarFile, "tarFile");
  Intrinsics.checkParameterIsNotNull(extractPath, "extractPath");

  logger.info("Extracting file: " + tarFile.toString());
  logger.info("Destination path: " + extractPath.toString());
  long start = System.currentTimeMillis();
  List untarCommand = Arrays.asList("tar", "-xzf", tarFile.toString(), "-C", extractPath.toString());
  Process untarProcess = (new ProcessBuilder(new String[0]))
      .command(untarCommand)
      .redirectErrorStream(true)
      .start();
  Intrinsics.checkExpressionValueIsNotNull(untarProcess, "untarProcess");
  this.waitAndCheckProcessOutput(untarProcess, "tar -xzf " + tarFile.toString() + " -C " + extractPath.toString(), 15L);

  logger.info("Running chmod on folder:" + extractPath.toString());
  List chmodCommand = Arrays.asList("chmod", "-R", "0777", extractPath.toString());
  Process chmodProcess = (new ProcessBuilder(new String[0]))
      .command(chmodCommand)
      .redirectErrorStream(true)
      .start();
  Intrinsics.checkExpressionValueIsNotNull(chmodProcess, "chmodProcess");
  this.waitAndCheckProcessOutput(chmodProcess, "chmod -R 0777 " + extractPath.toString(), 15L);
  logger.info("Extracted in " + this.printTime(System.currentTimeMillis() - start));
}

public final void waitAndCheckProcessOutput(@NotNull Process process, @NotNull String command, long timeoutInMinutes) {
  Intrinsics.checkParameterIsNotNull(process, "process");
  Intrinsics.checkParameterIsNotNull(command, "command");
  try {
      boolean finished = process.waitFor(timeoutInMinutes, TimeUnit.MINUTES);
      if (!finished) {
        logger.info("Timed out running command " + command);
      }
      String output = new BufferedReader(new InputStreamReader(process.getInputStream()))
        .lines()
        .collect(Collectors.joining());
      int exitCode = process.exitValue();
      if (exitCode != 0) {
        logger.info("Got exit code " + exitCode + " running command " + command + "\nGot output:\n" + output);
      }
  } catch (InterruptedException var8) {
      logger.info("Interrupted running command " + command + var8);
  }

}

@NotNull
public final String print(long timeInMillis) {
  Duration duration = Duration.ofMillis(timeInMillis);
  long minutes = duration.toMinutes();
  duration = duration.minusMinutes(minutes);
  long seconds = duration.getSeconds();
  duration = duration.minusSeconds(seconds);
  long millis = duration.toMillis();
  return minutes + "m " + seconds + "." + millis + "s";
}

जावा कोड:

public static synchronized Path untarFile(Path tarFile, Path extractPath) throws IOException {
    logger.info("Extracting file: " + tarFile.toString());
    logger.info("Destination path: " + extractPath.toString());
    long start = System.currentTimeMillis();
    List<String> untarCommand = Arrays.asList("tar", "-xzf", tarFile.toString(), "-C", extractPath.toString());
    Process untarProcess = new ProcessBuilder()
        .command(untarCommand)
        .redirectErrorStream(true)
        .start();
    ProcessUtil.waitAndCheckProcessOutput(untarProcess, "tar -xzf " + tarFile.toString() + " -C " + extractPath.toString());

    logger.info("Running chmod on folder:" + extractPath.toString());
    List<String> chmodCommand = Arrays.asList("chmod", "-R", "0777", extractPath.toString());
    Process chmodProcess = new ProcessBuilder()
        .command(chmodCommand)
        .redirectErrorStream(true)
        .start();
    ProcessUtil.waitAndCheckProcessOutput(chmodProcess, "chmod -R 0777 " + extractPath.toString());

    logger.info("Extracted in " + TimeUtil.print(System.currentTimeMillis() - start));
    return extractPath;
}

// In ProcessUtil.java
public static void waitAndCheckProcessOutput(Process process, String command, long timeoutInMinutes) {
    try {
        boolean finished = process.waitFor(timeoutInMinutes, TimeUnit.MINUTES);
        if (!finished) {
            logger.info("Timed out running command " + command);
        }
        String output = new BufferedReader(new InputStreamReader(process.getInputStream()))
            .lines()
            .collect(Collectors.joining());
        int exitCode = process.exitValue();
        if (exitCode != 0) {
            logger.info("Got exit code " + exitCode + " running command " + command
                                            + "\nGot output:\n" + output);
        }
    } catch (InterruptedException e) {
        logger.info("Interrupted running command " + command, e);
    }
}

// in TimeUtil.java
public static String print(long timeInMillis) {
    Duration duration = Duration.ofMillis(timeInMillis);
    long minutes = duration.toMinutes();
    duration = duration.minusMinutes(minutes);
    long seconds = duration.getSeconds();
    duration = duration.minusSeconds(seconds);
    long millis = duration.toMillis();
    return minutes + "m " + seconds + "." + millis + "s";
}

इसे इस तरह कहा जाता है:

IntStream.range(0, count).parallel().forEach{ unsynchronizedMethod() }

जहां इस unsynchronizedMethod के भीतर ExtractTar को कॉल किया जाता है।

मुझे 95% यकीन है कि आंतरिक पुस्तकालय कॉल में मंदी नहीं हो रही है, क्योंकि चेक किए गए मूल्यों में से कोई भी कभी भी शून्य नहीं होना चाहिए।

यह भी ध्यान रखना दिलचस्प है कि धीमी मात्रा में थ्रेड्स के लिए मंदी नहीं होती है, जैसे कि 2. जैसे-जैसे थ्रेड्स की संख्या बढ़ती है, प्रदर्शन बिगड़ता है, जिससे मुझे संदेह होता है कि यह वास्तव में एक समवर्ती समस्या है।

मैंने कोटलिन-डीकंपिल्ड-टू-जावा कोड चलाने की भी कोशिश की है, आंतरिक लाइब्रेरी कॉल को अलग करना, और उस कोड का मूल जावा कोड के समान प्रदर्शन है।

0
asdfjhjalshdf 19 सितंबर 2018, 21:14

1 उत्तर

सबसे बढ़िया उत्तर

अर्क को में ले जाकर फिक्स्ड

companion object {}

निश्चित नहीं है कि इसने समस्या को ठीक क्यों किया, लेकिन इसने किया

0
asdfjhjalshdf 20 सितंबर 2018, 23:50