2010-06-01 39 views
1

我知道这是在黑暗中的绝对镜头,但我们绝对困惑。从Java推出的Perl需要永远

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

两种情况下的记录都是相同的,并且脚本在两种情况下都使用相同的参数运行。

该脚本,如Oracle数据库访问,一些SCP的,等一些复杂的东西,但同样,它在这两种情况下完全相同的动作。

我们很难过。有没有人遇到类似的情况?如果不是,如果您遇到同样的情况,您会如何考虑调试它?

+5

该脚本是否完成或在一小时后仍在运行?你如何运行脚本?你读过脚本的输出(Process#getInputStream(),Process#getErrorSteam())吗?我想我记得一个进程可能被阻塞,如果它的缓冲区没有被读取。 – sfussenegger 2010-06-01 14:31:19

+0

它在两种情况下运行在相同的硬件上吗? – Zaid 2010-06-01 14:32:04

+0

你如何衡量时间流逝? – LB40 2010-06-01 14:36:48

回答

0

为了使这个线程结束,最终的原因是流氓进程消耗了太多的CPU。从命令行启动时,脚本具有普通优先级。从Java启动时,该脚本的优先级较低,因此需要永久执行。抛弃我们的是,Java代码不只是执行脚本,而是通过SSH发出了我们交互发布的相同命令。因此,我们并没有预料到优先权的差异。

3

我想你已经抛弃了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 heretime java Exec perl script.pl insert args here,会发生什么?如果这个世界是理智的,那么它们几乎是同时发生的(除了第二个需要额外的几秒来启动Java),并且如果是这样的话,那么逐步开始调整Exec类来越来越像你的部署环境,并且看看它何时开始需要很长时间。

如果Exec上面确实需要更长的时间,开始记录像Perl脚本疯狂,让你看到哪些动作需要较长时间。顺便说一下,也请登录Java包装器,以便了解Perl启动是否需要很长时间。

2

一种可能性是,你可以将这个系统试图通过运行一个大的Java应用程序,并且没有足够的内存的系统上大量的Perl程序鞭打。

使用监视工具如topvmstat -5iostat -5等来尝试找出缓慢是否对应于某些操作系统级病理将是一个好主意。

4

子proceses其产生控制台输出可以阻止(和死锁),如果他们的标准输出/ 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(); 
+0

我的代码相应地更新。 (而且它并没有做出我们使用US-ASCII的假设) – gustafc 2010-06-02 07:21:23

+0

哦,当然,这是一个说明性的例子。大多数人创建一个StreamFluser类并且即时一两个。 – Justin 2010-06-02 13:58:17