本文介绍了如何在不阻塞Haskell中的线程的情况下从进程中获取输出的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧! 问题描述 29岁程序员,3月因学历无情被辞! 子进程是通过 $ b import System.Environment import System.Timeout(code>超时)导入Control.Concurrent 导入Control.Concurrent(forkIO,threadDelay,killThread)导入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 - 发送命令 - 阻止直到收到响应 contents putStrLn $got:++内容 hClose inp - 并关闭管道 putStrLnwai ting for process to terminate waitForProcess phandle - 非阻塞IO,发送一行,等待响应超时期间 main2 cmd tmicros = do r let(Just inp,Just outp,_,phandle)= r hSetBuffering inp NoBuffering hPutStrLn inp cmd - 发送命令,将在4秒后响应 mvar tid > = putMVar mvar - 等待响应超时时间结果< - 超时tmicros(takeMVar mvar) killThread tid 结果无 - > putStrLn超时只需x - > putStrLn $got:++ x h关闭inp - 并关闭管道 putStrLn等待进程终止 waitForProcess phandle - 非块IO,发送一行,每超时报告进度 main3 cmd tmicros = do r let(Just inp,Just outp,_,phandle)= r hSetBuffering inp NoBuffering hPutStrLn inp cmd - 发送命令 mvar< - newEmptyMVar tid< - forkIO $ hGetLine outp>> = putMVar mvar - 循环直到接收到响应;每个超时时间报告进度 let循环=执行结果< - 超时tmicros(takeMVar mvar)结果 Nothing - > putStrLn仍在等待......>>循环只需x - >返回x x< - 循环 killThread tid putStrLn $got:++ x hClose inp - 并关闭管道 putStrLn等待进程终止 waitForProcess phandle { - 用法:./prog哪个延迟超时 其中 which =要运行的主例程:1,2或3 delay =发送到计算脚本的延迟秒数 timeout =等待响应的超时秒数 例如: ./prog 1 4 3 - 注意:main1 ./prog 2 2 3 - 应该超时 ./prog 2 4 3 - 应得到回应 ./prog 3 4 1 - 应该看到仍在等待......几次 - } main = do (which:vtime:tout:_)< - fmap(map read)getArgs let cmd =10++ show vtime tmicros = 1000000 * tout ::诠释案例哪 1 - > main1 cmd tmicros 2 - > main2 cmd tmicros 3 - > main3 cmd tmicros _ - >错误嗯? What is the best way to write to the stdin and read from the stdout of a subprocess without blocking?The subprocess was created via System.IO.createProcess which returns handles for writing to and reading from the subprocess. The writing and reading is done in text format.For example, my best attempt at doing non-blocking read is timeout 1 $ hGetLine out which returns a Just "some line" or Nothing if no line exists to be read. However, this seems an hack to me, so I am looking for a more "standard" way.Thanks 解决方案 Here are some examples of how to interact with a spawned process in a fashion mentioned by @jberryman.The program interacts with a script ./compute which simply reads lines from stdin in the form <x> <y> and returns x+1 after a delay of y seconds. More details at this gist.There are many caveats when interacting with spawned processes. In order to avoid "suffering from buffering" you need to flush the outgoing pipe whenever you send input and the spawned process needs to flush stdout every time it sends a response. Interacting with the process via a pseudo-tty is an alternative if you find that stdout is not flushed promptly enough.Also, the examples assume that closing the input pipe will lead to termination of the spawn process. If this is not the case you will have to send it a signal to ensure termination.Here is the example code - see the main routine at the end for sample invocations.import System.Environmentimport System.Timeout (timeout)import Control.Concurrentimport Control.Concurrent (forkIO, threadDelay, killThread)import Control.Concurrent.MVar (newEmptyMVar, putMVar, takeMVar)import System.Processimport System.IO-- blocking IOmain1 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 responsemain2 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 periodmain3 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 responseE.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中的线程的情况下从进程中获取输出的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持! 上岸,阿里云!
08-05 04:03