在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))
答案 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时遇到的问题相同,并且在所有函数调用结束时忘记了()
。它并行分配函数指针a
和b
,但实际上并没有调用它们。
如果您在Haskell中编写纯函数,则可以使用par
添加并行性,但它不适用于IO
,因为IO a
就像一个函数指针。您的代码并行“评估”a
和b
,但该评估的结果仍在等待您实际执行它。
对于位于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