在Haskell中同步并行进程

时间:2015-05-20 17:39:00

标签: haskell parallel-processing monads

在Haskell中,如何并行运行多个(monad?)函数(例如print)并按照完成时间的顺序查看它们的输出?我想要三个进程,每个进程最终都在打印函数中。

import Control.Parallel
main = a `par` b `pseq` (a,b)
    where
        a = print("ack",ack 3 10)
        b = print("fac",fac 42)

如果我不使用pseq,则会显示par组合中指定的最后一个。我想确保在程序结束之前完成所有进程。我尝试了这个,但它没有显示a,b:

的输出
...
main = a `par` b `pseq` print("done.")
...

注意:我的程序以以下行结束:

fac 0 = 1
fac n = n * fac (n-1)
ack 0 n = n+1
ack m 0 = ack (m-1) 1
ack m n = ack (m-1) (ack m (n-1))

2 个答案:

答案 0 :(得分:6)

不要同时使用Control.Parallel来运行IO操作。

Control.Concurrent.Async应该做你想做的事情 - Control.Parallel用于暗示可以同时评估哪些纯操作,而不是同时运行多个动作(monadic或其他)。

答案 1 :(得分:1)

在C系列语言中,这两行之间存在差异

a = foobar; // This just sets a to be a function pointer to foobar
b = foobar(); // This actually runs foobar and stores the result in `b`

您的代码基本上与您编写C时遇到的问题相同,并且在所有函数调用结束时忘记了()。它并行分配函数指针ab,但实际上并没有调用它们。

如果您在Haskell中编写纯函数,则可以使用par添加并行性,但它不适用于IO,因为IO a就像一个函数指针。您的代码并行“评估”ab,但该评估的结果仍在等待您实际执行它。

对于位于IO的代码,您必须导入Control.Concurrent并使用函数forkIO来创建新线程。然后因为子线程在主线程完成时全部自动死亡,你需要一些方法让主线程等待(我将在示例中使用MVar,因为它们是最简单可靠的方法)

import Control.Concurrent
import Control.Concurrent.MVar

main = do
  -- MVars have a type parameter because you can also use them to send data
  -- between threads, but in this example I'm basically just using them as locks
  await <- newEmptyMVar :: IO (MVar ())
  bwait <- newEmptyMVar :: IO (MVar ())
  forkIO $ print ("ack",ack 3 10) >> putMVar await ()
  forkIO $ print ("fac",fac 42) >> putMVar bwait ()
  takeMVar await
  takeMVar bwait