代码之家  ›  专栏  ›  技术社区  ›  wadesworld

从Java启动Perl需要很长时间

  •  1
  • wadesworld  · 技术社区  · 15 年前

    我知道这绝对是一个黑暗的镜头,但我们绝对困惑。

    Java(1.5)运行的perl(5.8.6)脚本需要一个多小时才能完成。同样的脚本,从命令行手动运行需要12分钟才能完成。这是在Linux主机上。

    该脚本执行一些复杂的操作,如oracledb访问、一些scp等,但在这两种情况下,它执行的操作完全相同。

    我们被难住了。有没有人遇到过类似的情况?如果没有,如果您面临同样的情况,您将如何考虑调试它?

    4 回复  |  直到 15 年前
        1
  •  4
  •   Justin    15 年前

    如果没有刷新stdout/stderror流,则产生控制台输出的子进程可以阻塞(和死锁)@gustafc,当子进程试图写入stdout/stderror时,提出的代码最终会阻塞子进程,并且流中没有空间(而且流没有由java提供服务)。

    Process p = startProcess();
    
    final InputStream stdout = p.getInputStream();
    final InputStream sterr = p.getErrorStream();
    
    new Thread() {
     public void run() {
      int c;
      while ((c = sterr.read()) != -1) {
       System.out.print((char)c);
      }
     }
    }.start();
    
    new Thread() {
     public void run() {
      int c;
      while ((c = sterr.read()) != -1) {
       System.out.print((char)c);
      }
     }
    }.start();
    
        2
  •  3
  •   gustafc    14 年前

    我假设您已经放弃了Java包装器碰巧作为其他东西同时运行的可能性,这会导致对某些稀缺资源的巨大争用?很好。

    public class Exec {
        public static void main(String[] args) throws Throwable{
            class Transfer implements Runnable {
                private final InputStream in; 
                private final OutputStream out; 
                public Transfer(InputStream i, OutputStream o){
                    in = i;
                    out = o;
                }
                public void run(){
                    try {
                        for (int i; (i = in.read()) != -1;) out.write(i);
                        out.close();
                        in.close();
                    } catch (IOException e) {
                        e.printStackTrace();
                    } 
                }
            }
            Process proc = new ProcessBuilder(args).start();
            new Thread(new Transfer(System.in, proc.getOutputStream())).start();
            new Thread(new Transfer(proc.getInputStream(), System.out)).start();
            new Thread(new Transfer(proc.getErrorStream(), System.err)).start();
            System.exit(proc.waitFor());
        }
    }
    

    ... 你比较一下 time perl script.pl insert args here time java Exec perl script.pl insert args here ,会发生什么?如果这个世界是正常的,那么它们需要大约相同的时间(除了第二个需要额外几秒钟的时间来启动Java),如果是这样的话,就逐渐开始适应 Exec 类以使其看起来越来越像您的部署环境,并查看它何时开始花费很长时间。

    执行 上面提到的确实需要更长的时间,在Perl脚本中疯狂地开始日志记录,这样您就可以看到哪些操作需要更长的时间。顺便说一句,也要登录Java包装器,这样就可以看到Perl启动是否需要很长时间。

        3
  •  2
  •   Stephen C    15 年前

    最好使用监视实用程序,如 top vmstat -5 iostat -5 等来尝试找出慢度是否与操作系统级别的病理学对应。

        4
  •  0
  •   wadesworld    14 年前

    为了结束这个线程,最终的原因是流氓进程消耗了太多的CPU。从命令行启动时,脚本具有正常优先级。当从Java启动时,脚本的优先级很低,因此需要很长时间才能执行。让我们感到困惑的是,Java代码不仅仅是执行脚本,它还通过SSH发出与我们交互发出的命令相同的命令。因此,我们没有预料到优先级的差异。