使用Java ProcessBuilder运行haskell可执行文件:为什么hGetLine仅在关闭outputStream时返回?

时间:2012-03-31 13:53:56

标签: java haskell

我将FM-SBLEX Saldo程序包装在Java库中。

Saldo是用Haskell编写的,并且在词典中查找stdin上给出的行,例如

echo "ord"|./sblex/bin/saldo dicts/saldo.dict

将以下内容输出到stdout

{"ord":{"s_1":{"word":"ord","head":"sanna mina ord","pos":"abm","param":"invar 1:3-3","inhs":[],"id":"sanna_mina_ord..abm.1","p":"abm_i_till_exempel","attr":"3"},...

如果我用

运行它
./sblex/bin/saldo dicts/saldo.dict

它会对我在控制台输入的每一行进行查找,直到我发送EOF。

在我的Java库中,我使用ProcessBuilder启动它,并设置一个线程将stdout和stderr转储到我的程序的stdout,另一个线程写一个单词和一个换行符,然后刷新outputStream

在控制台上,saldo每次按回车键都会返回结果,但在我的包装器中,只有在关闭outputStream后才会返回所有输入的结果(请参阅下一个代码块中注释掉.close())

    ProcessBuilder pb = new ProcessBuilder(binPath, dictPath);

    pb.redirectErrorStream(true);
    saldoProcess = pb.start();

    new Thread(new Reader(saldoProcess.getInputStream())).start();
    new Thread(new Writer(saldoProcess.getOutputStream())).start();

    saldoProcess.waitFor();
    System.out.println("saldo exited.");
    Thread.sleep(2000);

Writer的运行覆盖:

    public void run() {
        try {
            outputStream.write("ord\n".getBytes());
            outputStream.flush();
            //outputStream.close();
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }

读取输入的Haskell代码

run' :: Language a => a -> (String -> [Tok]) -> (String -> [[String]]) -> AnaType -> Stats -> IO Stats
run' l tokenizer f a st = 
 do b <- hIsEOF stdin
    if b then return st 
     else do 
       s <- hGetLine stdin
       analyze l a f (tokenizer s) st >>= run' l tokenizer f a

如果binPath =“cat”和dictPath =“ - ”我的java程序在每次刷新后输出输入。知道为什么这个haskell程序只关闭outputStream之后才处理输入?

注意:正如答案所示,不是hGetLine没有返回(正如我所假设的那样),而是缓存的输出,因为我正在使用的Haskell实现默认为阻塞缓冲区,如果它不是从控制台。

1 个答案:

答案 0 :(得分:4)

您的Haskell程序可能正在缓冲其输出。 (当写入终端时进行行缓冲,写入其他任何内容时进行缓冲。)

尝试添加

hSetBuffering stdout LineBuffering

在计划开始附近。

More about buffering in Haskell.

(编辑回应Daniel Wagner的评论。)