Runtime.exec使用错误导致延迟.md

这篇文章是纪录了一个bug解决的过程,但是我还是没有能够真正地找出bug的缘由。希望大牛能够详细解释。

问题的发现

当接触的系统越来越大的时候,对于系统的性能越来越高的时候,找到表面问题的真正原因就慢慢地成为了一个比较麻烦的问题。说实话,一开始我一直不知道是因为Runtime.getRuntime().exec()导致服务处理时间缓慢。发现这个原因倒是花了不少时间。

为了方便,我直接就用java调用python脚本。用python脚本处理做核心的机器学习算法的东西。而java调用python脚本,我直接就采用了Runtime.getRuntime().exec(),这个方式类似于直接使用了shell来执行。一开始使用的挺好,也没有注意一些细节的问题,慢慢地用着用着,发现有一台机器处理相同地人脸头像比另外一台慢。从经验上考虑过很多的可能情况,但是都不是问题的真正原因。但每一个误判,我感觉都非常值得反思。

网络问题

由于我使用了内网穿透工具,本身对工具性能也不熟悉,刚开始的时候立刻就想到了是不是因为使用了内网穿透工具,导致网速太慢了。由于这个问题我几乎就无法解决,所以我一想到这个原因,就没有再去想办法解决了。后面直接发现直接从访问的结果仍然是一样的慢。其实这个地方我应该去验证一下,直接从内网访问,看一下速度。这样就能够避免误判带来的问题了。

机器配置问题

由于两台机器配置的时候还是存在一点点不同,我后面又想是不是一台机器配置出现问题?检查了半天还是不能确认是不是机器配置不同,安装的内容不同导致出现了问题。由于没什么时间,干脆我又扔一边去了。

某些随机因素

因为一台机器执行快速,另外一台执行缓慢,而出现这种诡异的问题,很容易就让人想到是不是代码库因为某些原因,导致了这种情况。而往往这种问题就基本是没有办法搞定了。其实我还是一个新手的时候,我总是怀疑某些问题是因为一些系统错误,随机因素导致的。但是结果往往是自己的错误。因为有了之前的经验,我潜意识就感觉可能是自己哪段代码出现了错误。

之后通过对代码片段打印时间,每一段执行完都打印时间点。最后查看日志发现,就是在调用process.waitfor的时候,python程序已经返回了,但是java程序仍然没有任何响应,还是在wait。这样才发现了这个问题。然后通过在网上搜索Runtime.getRuntime()执行程序应该注意的事项,找到问题的关键。我使用waitfor,之后再去读取python程序的输出,但是因为输出一直没有被读取,缓冲区满了,程序就被阻塞。

getRuntime().exec

getRuntime().exec会返回一个Process,在jdk文档中有说明,Process的缓冲区是有限的,如果输出的内容太多,程序就会被阻塞掉。

我一开始的程序是像下面这样的:

?    ?try {
?    ?         final Process p = Runtime.getRuntime().exec("python test.py");
?    ?    ?    ? p.waitFor();
?    ?         BufferedReader br = new BufferedReader(new InputStreamReader(p.getInputStream()));
?    ?         try {
?    ?                      while (br.readLine() != null)
?    ?                          ;
?    ?                      br.close();
?    ?          } catch (IOException e) {
?    ?               e.printStackTrace();
?    ?          }
?    ?} catch (Exception e) {
?    ?          e.printStackTrace();
?    ?}

这样的结果就是一台机器在waitFor那里被卡住很长一段时间。然后参考了网上给的原因,将程序改成下面这样:

    try {
             final Process p = Runtime.getRuntime().exec("python test.py");

             BufferedReader br = new BufferedReader(new InputStreamReader(p.getInputStream()));
             try {
                          while (br.readLine() != null)
                              ;
                          br.close();
              } catch (IOException e) {
                   e.printStackTrace();
              }
              p.waitFor();
    } catch (Exception e) {
              e.printStackTrace();
    }

这样程序就不会长时间卡在那里。甚至于去掉p。waitFor程序也是OK的。因为程序结束后,Stream就被close掉了。网上很多人是遇到了因为exec执行的程序出现了错误,结果Error信息占满了缓冲区,导致程序被挂起。

原因探究

从网上看的那些信息只能让我猜测可能是因为打印信息太多,没有及时读出,导致程序卡住。但是我心里还是有疑问,为什么一台机器ok,另外一台机器会卡住,过很长时间才返回呢?这里面具体的细节方面的原因我觉得我还是没有找对。其实我python程序打印的东西也不多的。

另外也有一个可能是python程序执行完后,很长时间都没有完全返回。这也是一个猜测的原因。虽然我按照网上的方式暂时解决了问题,但这些原因其实我觉得都不够充分,希望有人能够给出正确的解释。基础真的要牢靠。

时间: 2024-11-05 13:33:44

Runtime.exec使用错误导致延迟.md的相关文章

【解决】OCI runtime exec failed......executable file not found in $PATH": unknown

[问题]使用docker exec + sh进入容器时报错 [[email protected] home]# docker exec -it container-test bash OCI runtime exec failed: exec failed: container_linux.go:346: starting container process caused "exec: \"bash\": executable file not found in $PATH&

Runtime.exec() sucks!!!!

自己项目中使用到了 Runtime rt = Runtime.getRuntime(); Process p = rt.exec("query session");p.waitFor(); 结果在不同的windows 操作系统中,程序的运行不一致,在windows server 2008上可以很好的运行,但是到了windows7上去卡死了!!!!!!!!!!!!!!!!!!!!!! p.waitFor() 卡死了或者报错: [ERROR] xxxxx Thread-0 - Cannot

为什么Runtime.exec("ls")没有任何输出_JAVA基础教程

本文针对为什么Runtime.exec("ls")没有任何输出作出解答,解答如下: 调用Runtime.exec方法将产生一个本地的进程,并返回一个Process子类的实例,该实例可用于控制进程或取得进程的相关信息. 由于调用Runtime.exec方法所创建的子进程没有自己的终端或控制台,因此该子进程的标准IO(如stdin,stdou,stderr)都通过Process.getOutputStream(),Process.getInputStream(), Process.getE

使用Runtime.exec()运行windwos dos或linux shell命令

使用Runtime.exec()运行windwos dos或linux shell命令,按实际情况具体测试 实例代码: package com.bookoo.test.command; import java.io.BufferedReader; import java.io.BufferedWriter; import java.io.IOException; import java.io.InputStreamReader; import java.io.OutputStreamWriter

[转]Java中Runtime.exec的一些事

0 预备知识 1 不正确的调用exitValue 2不正确的调用waitFor 3 一种可接受的调用方式 4 调用认为是可执行程序的时候容易发生的错误 5 window执行的良好示例 6 不良好的重定向命令输出 7 良好的重定向输出示例 8 总结 9 问答 0 预备知识 Runtime类是一个与JVM运行时环境有关的Singleton类,有以下几个值得注意的地方: 0.1 Runtime.getRuntime()可以取得当前JVM的运行时环境,这也是在Java中唯一得到运行时环境的方法. 0.2

java Runtime.exec() 执行问题

Runtime.exec() 不等同于直接执行command line命令! Runtime.exec()很有局限性,对有些命令不能直接把command line里的内容当作String参数传给exec(). 比如重定向等命令.举个例子: javap -l xxx > output.txt 这时要用到exec的第二种重载,即input 参数为String[]: Process p = Runtime.getRuntime().exec(new String[]{"/bin/sh"

Runtime.exec()

关于RunTime类的介绍: 1 /** 2 * Every Java application has a single instance of class 3 * <code>Runtime</code> that allows the application to interface with 4 * the environment in which the application is running. The current 5 * runtime can be obtai

64位xp上java Runtime.exec无法正常运行的问题

有一段简单的java代码如下 package com.dongjak.test; import java.io.IOException; public class Test { public static void main(String[] args) { // ProcessUtils.shutdown(1); Runtime runtime = Runtime.getRuntime(); try { runtime.exec("shutdown -f -s -t 1"); } c

Java魔法堂:找外援的利器——Runtime.exec详解

一.前言 Java虽然五脏俱全但总有软肋,譬如获取CPU等硬件信息,当然我们可以通过JNI调用C/C++来获取,但对于对C/C++和Windows API不熟的码农是一系列复杂的学习和踩坑过程.那能不能通过简单一些.学习成本低一些的方式呢?答案是肯定的,在功能实现放在首位的情况下,借他山之石是最简洁有力的做法.而 Runtime.exec方法 就为我们打开这么的一条路了. 二.认识 java.lang.Runtime.exec方法    作用:用于调用外部程序,并重定向外部程序的标准输入.标准输