簡體   English   中英

如何將輸出從IO操作傳輸到haskell中的進程

[英]How to pipe output from an IO action into a process in haskell

我想創建一個進程並定期將我的haskell程序中的一些文本寫入進程的stdin(來自IO操作)。

以下在GHCi中正常工作,但在構建和運行時無法正常工作。 在GHCi中,一切都運行良好,IO動作的價值定期提供。 然而,當構建並運行時,它似乎在寫入進程的標准輸入時暫停任意長時間。

我已經使用CreateProcess (來自System.Process )來創建句柄並嘗試了hPutStrLn (bufferent設置為NoBuffering - LineBuffering沒有工作)。

所以我正在嘗試process-streaming包和pipes但似乎無法完成任何工作。

真正的問題是:我如何從haskell創建一個進程並定期寫入它?

展示此行為的最小示例:

import System.Process
import Data.IORef
import qualified Data.Text as T  -- from the text package
import qualified Data.Text.IO as TIO
import Control.Concurrent.Timer  -- from the timers package
import Control.Concurrent.Suspend -- from the suspend package

main = do
    (Just hin, _,_,_) <- createProcess_ "bgProcess" $
        (System.Process.proc "grep"  ["10"]) { std_in = CreatePipe }

    ref <- newIORef 0 :: IO (IORef Int)
    flip repeatedTimer (msDelay 1000) $ do
        x <- atomicModifyIORef' ref $ \x -> (x + 1, x)
        hSetBuffering hin NoBuffering
        TIO.hPutStrLn hin $ T.pack $ show x

任何幫助將不勝感激。

這是一個管道Producer ,它發出一系列具有第二個延遲的數字:

{-# language NumDecimals #-}
import Control.Concurrent
import Pipes
import qualified Data.ByteString.Char8 as Bytes

periodic :: Producer Bytes.ByteString IO ()
periodic = go 0
    where
        go n = do
            d <- liftIO (pure (Bytes.pack (show n ++ "\n"))) -- put your IO action here
            Pipes.yield d
            liftIO (threadDelay 1e6)
            go (succ n)

並且,使用流程流 ,我們可以將生產者提供給外部流程,如下所示:

import System.Process.Streaming

main :: IO ()
main = do
    executeInteractive (shell "grep 10"){ std_in = CreatePipe } (feedProducer periodic)

我使用了executeInteractive ,它將std_in自動設置為NoBuffering

此外,如果管道std_out並希望立即處理每個匹配,請確保將--line-buffered選項傳遞給grep(或使用stdbuf命令)以確保匹配在輸出中立即可用。

使用threadDelay怎么樣,例如:

import Control.Monad (forever)
import Control.Concurrent (threadDelay)
...

forever $ do
    x <- atomicModifyIORef' ref $ \x -> (x + 1, x)
    hSetBuffering hin NoBuffering
    TIO.hPutStrLn hin $ T.pack $ show x
    threadDelay 1000000  -- 1 sec

如果您需要同時執行其他工作,請在另一個線程中生成此項。

您可以通過以下方式刪除他對IORef的需求:

loop h x = do 
    hSetBuffering h NoBuffering
    TIO.hPutStrLn h $ T.pack $ show x
    threadDelay 1000000
    loop h (x+1)

當然,您只需要執行一次hSetBuffering - 例如在您進入循環之前執行此操作。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM