gpt4 book ai didi

haskell - 如何在不阻塞 Haskell 线程的情况下从进程中检索输出

转载 作者:行者123 更新时间:2023-12-01 15:56:35 28 4
gpt4 key购买 nike

在不阻塞的情况下写入标准输入和从子进程的标准输出读取的最佳方法是什么?

子进程是通过 System.IO.createProcess 创建的,它返回用于写入子进程和从子进程读取的句柄。写作和阅读以文本格式完成。

例如,我最好的非阻塞读取尝试是 timeout 1 $ hGetLine out,它返回一个 Just "some line"Nothing code> 如果没有要读取的行。然而,这对我来说似乎是一种 hack,所以我正在寻找一种更“标准”的方式。

谢谢

最佳答案

下面是一些示例,说明如何以@jberryman 提到的方式与生成的进程进行交互。

程序与脚本交互./compute它只是以 <x> <y> 的形式从 stdin 中读取行并在延迟 y 秒后返回 x+1。更多详情,请访问 this gist .

与派生进程交互时有很多注意事项。为了避免“遭受缓冲”,您需要在每次发送输入时刷新传出管道,并且生成的进程在每次发送响应时都需要刷新标准输出。如果您发现 stdout 刷新不够及时,则可以通过伪 tty 与进程交互。

此外,示例还假设关闭输入管道将导致生成进程终止。如果不是这种情况,您将必须向它发送信号以确保终止。

这是示例代码 - 请参阅 main示例调用的最后例程。

import System.Environment
import System.Timeout (timeout)
import Control.Concurrent
import Control.Concurrent (forkIO, threadDelay, killThread)
import Control.Concurrent.MVar (newEmptyMVar, putMVar, takeMVar)

import System.Process
import System.IO

-- blocking IO
main1 cmd tmicros = do
r <- createProcess (proc "./compute" []) { std_out = CreatePipe, std_in = CreatePipe }
let (Just inp, Just outp, _, phandle) = r

hSetBuffering inp NoBuffering
hPutStrLn inp cmd -- send a command

-- block until the response is received
contents <- hGetLine outp
putStrLn $ "got: " ++ contents

hClose inp -- and close the pipe
putStrLn "waiting for process to terminate"
waitForProcess phandle

-- non-blocking IO, send one line, wait the timeout period for a response
main2 cmd tmicros = do
r <- createProcess (proc "./compute" []) { std_out = CreatePipe, std_in = CreatePipe }
let (Just inp, Just outp, _, phandle) = r

hSetBuffering inp NoBuffering
hPutStrLn inp cmd -- send a command, will respond after 4 seconds

mvar <- newEmptyMVar
tid <- forkIO $ hGetLine outp >>= putMVar mvar

-- wait the timeout period for the response
result <- timeout tmicros (takeMVar mvar)
killThread tid

case result of
Nothing -> putStrLn "timed out"
Just x -> putStrLn $ "got: " ++ x

hClose inp -- and close the pipe
putStrLn "waiting for process to terminate"
waitForProcess phandle

-- non-block IO, send one line, report progress every timeout period
main3 cmd tmicros = do
r <- createProcess (proc "./compute" []) { std_out = CreatePipe, std_in = CreatePipe }
let (Just inp, Just outp, _, phandle) = r

hSetBuffering inp NoBuffering
hPutStrLn inp cmd -- send command

mvar <- newEmptyMVar
tid <- forkIO $ hGetLine outp >>= putMVar mvar

-- loop until response received; report progress every timeout period
let loop = do result <- timeout tmicros (takeMVar mvar)
case result of
Nothing -> putStrLn "still waiting..." >> loop
Just x -> return x
x <- loop
killThread tid

putStrLn $ "got: " ++ x

hClose inp -- and close the pipe
putStrLn "waiting for process to terminate"
waitForProcess phandle

{-

Usage: ./prog which delay timeout

where
which = main routine to run: 1, 2 or 3
delay = delay in seconds to send to compute script
timeout = timeout in seconds to wait for response

E.g.:

./prog 1 4 3 -- note: timeout is ignored for main1
./prog 2 2 3 -- should timeout
./prog 2 4 3 -- should get response
./prog 3 4 1 -- should see "still waiting..." a couple of times

-}

main = do
(which : vtime : tout : _) <- fmap (map read) getArgs
let cmd = "10 " ++ show vtime
tmicros = 1000000*tout :: Int
case which of
1 -> main1 cmd tmicros
2 -> main2 cmd tmicros
3 -> main3 cmd tmicros
_ -> error "huh?"

关于haskell - 如何在不阻塞 Haskell 线程的情况下从进程中检索输出,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/33225837/

28 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com