首页 > 解决方案 > 使用 Process builder 从 Java 进程调用的 Perl 脚本挂起(消耗错误,在单独的线程中输出流)

问题描述

我正在尝试从这样的 Java 代码运行 perl 程序:

package com.test;

import java.io.IOException;
import java.io.InputStream;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;

public class PerlExecutor {

   static ExecutorService pool = Executors.newFixedThreadPool(3);

   public static void main(String[] args) throws Exception {
       System.out.println("Running perl script " + args[0]);
       executeProcess(args[0]);
       System.out.println("Done running perl script");
       pool.shutdownNow();
   }

  private static void executeProcess(String perlScript) throws Exception {

     System.out.println("Execute process " + perlScript);

     String[] command = new String[]{"perl", perlScript};
     ProcessBuilder pb = new ProcessBuilder(command);
     final Process process = pb.start();
     process.getOutputStream().close();

     Callable<Integer> callable = new Callable<Integer>() {

        public Integer call() throws Exception {
            int exitCode = process.waitFor();
            return (Integer) exitCode;
        }
    };
    Callable<Boolean> taskOutputStreamCallable = new Callable<Boolean>() {
        @Override
        public Boolean call() throws Exception {
            System.out.println("OutputStreamCallable started");
            readStream(process.getInputStream(), "OUT");
            System.out.println("OutputStreamCallable finished");
            return true;
        }
    };

    Callable<Boolean> taskErrorStreamCallable = new Callable<Boolean>() {

        @Override
        public Boolean call() throws Exception {
            System.out.println("ErrorStreamCallable started");
            readStream(process.getErrorStream(), "ERR");
            System.out.println("ErrorStreamCallable finished");
            return true;
        }
    };

    pool.submit(taskErrorStreamCallable);
    pool.submit(taskOutputStreamCallable);
    Future<Integer> f = pool.submit(callable);

    f.get();
}

 private static void readStream(InputStream inputStream, String type) throws 
 IOException {

    System.out.println("Reading stream " + type);

    try {

        int data = inputStream.read();
        System.out.println((char) data);
        while (data != -1) {
            System.out.println((char) data);
            data = inputStream.read();
        }

    } catch (Exception e) {
        e.printStackTrace();
    } finally {
        inputStream.close();
    }
    System.out.println("finished reading stream");
  } 
}

这是我的 perl 代码:

#!/usr/local/bin/perl

print "task START \n";

$a = 10;

while(1) {
 print  "Value of a: $a\n";
 $a = $a + 1;
 sleep(10);
}

如您所见,我已经消耗了输出和错误流,并按照建议关闭了标准输入Here

我注意到的是:

  1. perl 程序如果单独运行,则不会挂起。
  2. 如果 perl 程序是从 java 运行的,它会挂起而不会从 perl 程序中打印任何内容。
  3. 但是,如果我在顶部的 perl 脚本中添加 $|++ ,它会起作用。我的印象是 perl 打印语句中的换行符也应该刷新缓冲区,但显然这似乎没有发生,或者我错过了一些东西。
  4. 如果我取消睡眠 - 它再次起作用。

我被难住了,我已经完成了到目前为止我找到的链接中建议的所有内容..有人可以在这里给我指点吗?这里有一些 sleep 和 buffers 的组合似乎导致它失败。

标签: javaperl

解决方案


推荐阅读