读取使用createProcess获得的几行管道,然后关闭它

时间:2017-11-01 13:25:22

标签: haskell process io ipc

我有一个产生如下过程的函数:

(_, Just outh, _, ph) <- createProcess $
    (proc "someproc" []) { std_out = CreatePipe }
line <- hGetLine outh
doSomeComputationOn line
-- ... 'outh' is not read anymore from here onwards

创建"someproc",然后父项从中读取line以获取一些信息,然后忘记句柄为outh的管道。

现在的问题是,如果没有读取管道,"someproc"会在它满后立即阻止。所以这要求父进程读取outh,即使它没有对它做任何事情。所以我的问题是:

  1. 这是获取子进程输出的第一行然后忘记额外输出的好方法吗?
  2. 在Haskell中有什么方法可以自动丢弃管道输入(甚至将其重定向到文件)?
  3. 到目前为止,我能看到解决此问题的唯一方法是生成一个新的线程,该线程不断尝试从outh读取(并且只丢弃输出),这表明我做错了什么。

    作为补充背景,此问题与this one

    有关

2 个答案:

答案 0 :(得分:1)

使用的替代方法取决于外部命令的行为。

如果您只是想打断它,可以hClose outh。这将关闭管道,并且外部命令对管道的进一步写入将失败并且管道损坏&#34;错误。大多数进程在收到此终止后终止。

如果您想要阅读并放弃输出,也可以这样做。也许最简单的方法是

do c <- hGetContents outh
   evaluate (length c)  -- force this to fetch all data
   doStuff              -- now we are sure that the remote end closed its output

应该在恒定的空间内运行。

如果您不想在执行doStuff之前等待流程结束,请将所有内容打包在forkIO中。

答案 1 :(得分:1)

  

现在的问题是,如果没有读取管道,&#34; someproc&#34;一旦满了就会阻止。 [...] Haskell有什么方法可以自动丢弃   输入到管道(甚至将其重定向到文件)?

有一个名为process-streaming进程的帮助程序库(由本答案的作者编写)试图做到这一点:即使用户传递了一个消耗流的函数,不会耗尽标准流,它会自动排空以避免潜在的死锁。

图书馆不直接使用句柄,但通过pipe接受foldl消费函数和adapter type折叠。

阅读第一行的一个例子:

import           Data.Text.Lazy
import qualified Pipes.Prelude
import           System.Process.Streaming      (CreateProcess,shell,
                                                piped,execute,foldOut,transduce1,withCont)
import           System.Process.Streaming.Text (utf8x,foldedLines)

program :: CreateProcess
program = piped $ shell "{ echo aaa ; echo bbbb ; }"

firstLine :: IO (Maybe Text)
firstLine = execute program streams
    where
    streams = foldOut
            . transduce1 utf8x
            . transduce1 foldedLines
            $ withCont Pipes.Prelude.head

尽管如此,该库的依赖性足迹要比 process 大得多。