2016-05-25 14 views
3

プロセスを作成し、自分のhaskellプログラムのテキストを(IOアクションの)プロセスのstdinに定期的に書きたいとします。IOアクションの出力をhaskellのプロセスにパイプする方法

以下はGHCiでは正しく動作しますが、ビルドして実行すると正しく動作しません。 GHCiではすべてが完全に機能し、IOアクションの値は定期的に入力されます。しかし、ビルドして実行すると、プロセスの標準入力に書き込むときには、長時間のうちに一時停止するように見えます。

私がハンドルを作成する(System.Processから)CreateProcessを使用し、(bufferentがNoBufferingに設定する - のいずれかLineBuffering didntの仕事)hPutStrLnを試みました。

私は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 

任意の助けを大幅に理解されるであろう。

答えて

0

あなたは、同時に他の作業を行う必要がある場合、別のスレッドで:例えば、

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 

スポーンこれをthreadDelayをオフ使用について。

あなたは彼がIORefのために必要な削除することができます。

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

そして、もちろん、あなたは一度だけhSetBufferingを行う必要があります - 例えばあなたがループに入る直前にそれを行います。

+0

threadDelayは、サスペンド(最小待機を指定する)を使用している理由のタイミングメカニズムとして非常に不正確です。私はhSetBufferingソリューションを試しましたが、違いはありませんでした。 –

+0

well - 'suspend'は' threadDelay'の観点から実装されています。... Haskellのすべてのタイミング遅延はほとんどあります。 – ErikR

+0

これは実際の質問に対処していますか(コンパイル時に任意の長い遅延があることを見つけることについて)まったくですか?それは唯一の文章の提案が含まれて表示されます。 –

2

これは秒の遅延を有する数列発するパイプ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) 

そして、process-streamingを使用して、我々は、このような外部プロセスにプロデューサを供給することができる:

import System.Process.Streaming 

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

私はexecuteInteractiveを使用しました。これはstd_inを自動的にNoBufferingに設定します。試合は、出力時にすぐに利用可能であることを確認することも

std_outあなたパイプ場合は、すぐに各試合を処理したい、grepを(またはstdbufコマンドを使用)する--line-bufferedオプションを渡すようにしてください。

+0

私はこのような答えを期待していました。私はできるだけ早くこれを試してみましょう(その4時はここに:) :) –

+0

それぞれが一致するようにするには '--line-buffered'オプションを' grep'に渡してください出力ですぐに利用できます。 – danidiaz

+0

ありがとうございました:)これはgrepの例(とcatの場合)で私のために働いていました。私の実際のアプリケーションはまだ私のコード内の何かのように見える古い動作を表示しています。私のアプリケーションをプロファイルして調べてみましょうが、これは私が必要としていた答えのようです。 –

関連する問題