[Haskell-beginners] How to wait till a process is finished before invoking the next one?

Daniel Fischer daniel.is.fischer at web.de
Thu May 7 16:04:51 EDT 2009


Am Donnerstag 07 Mai 2009 20:53:11 schrieb Thomas Friedrich:
> Hi Daniel and everyone,
>
> Thanks for the reply!
>
> I thought of using waitForProcess, and in fact an earlier version of the
> program did. However, as the program got more complex, I don't really
> see how this is still possible.
>
> For example the runProgram function looks like this:
>
> runProgram :: [String] -> IO ()
> runProgram [] = return ()
> runProgram (c:cs) = do
>   runCommand ("lalala " ++ c)
>   runProgram cs

You could have

   runCommand ("lalala " ++ c) >>= waitForProcess

in the penultimate line. That would ensure that the command has finished before its 
results are requested, but of course destroy all possibilities of parallelism :-(

Another option would be

runProgram [] = return []
runProgram (c:cs) = unsafeInterleaveIO $ do
    ph <- runCommand ("lalala " ++ c)
    phs <- runProgram cs
    return (ph:phs)

and then,
    processHandles <- runProgram blah
    mapM_ waitForProcess (processHandles)
    next step

that should work (I hope) and would allow the commands to be run in parallel while making 
sure all have finished before the next step is started.

>
> It might be possible to write the function runProgram in a way, so that
> it returns an expression of type [IO ProcessHandle] and then try to work
> from there.  But I have the feeling, that this will become messy very
> quickly, and there must be some more elegant way of doing this.  The
> other thing is that actually not all functions are able to return
> ProcessHandles, e.g.
>
> writeFeatures :: [String] -> IO ()
> writeFeatures cs = Exc.bracket (openFile training AppendMode) hClose (\h
> -> goo h)
>   where
>     goo h = go 1 cs
>       where
>         go :: Int -> [String] -> IO ()
>         go n [] = putStrLn "Features written."
>         go n (c:cs) = do
>           features <- makeFeatures n c    -- makeFeatures :: Int ->
> String -> IO String
>           hPutStr h features
>           go (n+1) cs
>
> And the file that is produced here is needed in the next function.

That can't appear in runProgram, though.

I'm not sure it would work, but you coud give

{-# LANGUAGE BangPatterns #-}

...
    !a <- writeFeatures blah
    more

or 
    go n (c:cs) = do
        features <- makeFeatures n c
        !a <- hPutStr h features
        go (n+1) cs

a try.

>
> I hoped to do something with forkIO, as I would like to parallelize the
> whole program at the end.  Especially the function runProgram would
> benefit hugely from this (I so don't have a clue how to do this yet;). I
> tried for example the following:
>
> main :: IO ()
> main = do
>  cs <- getArgs
>  p1 <- forkIO $ writeData cs
>  p2 <- forkIO $ runProgram cs
>  p3 <- forkIO $ writeFeatures cs
>  p4 <- forkIO $ runTestOnFeatures
>  seq p1 (seq p2 (seq p3 (seq p4 (putStrLn "Done"))))
>
> But that of course doesn't work, because now I am not actually
> requesting anything.  The program does in fact nothing, apart from
> printing out "Done".

Huh. There doesn't seem to be a wait function for ThreadIds, so I guess you would have to 
communicate via MVars, QSemNs or some such means to signal that one task has been 
completed and the next can be started.

>
> Any ideas?
>
> Cheers,
> Thomas




More information about the Beginners mailing list