【发布时间】:2018-06-14 03:32:16
【问题描述】:
我有一个代表 shell 命令的字符串列表,我想同时执行 10 个。这是我第一次真正尝试在 Haskell 中进行并发编程,但我遇到了一些麻烦。
我的想法是将列表分成十个元素的子列表,然后mapM_ 一个函数同时生成十个命令中的每一个,等待每个命令完成,然后再继续下一组十个。然而,我使用/采用的每种不同的库/方法似乎只是同时启动列表中的每个命令。
假设我有一个最简单的函数来执行一个shell命令:
import System.Process
execShellCommand :: String -> IO ()
execShellCommand cmd = void $ createProcess (shell cmd)
天真的方法
import Control.Monad
import Data.List.Split.Internals
runChunks :: [String] -> IO ()
runChunks as = mapM_ (mapM_ execShellCommand) $ chunksOf 10 as
一次执行列表中的所有命令(我尝试使用 Conduit.Process 中的 waitFor 函数,结果相似)。让我们尝试更周到一点,将函数execShellCommand重新定义为使用Control.Concurrent:
import Control.Concurrent
execShellCommand :: String -> IO ()
execShellCommand cmd = do
m <- newEmptyMVar
r <- void $ createProcess (shell cmd)
forkIO $ putMVar m r
takeMVar m
runChunks :: [String] -> IO ()
runChunks [] = return ()
runChunks as = do
mapM_ execShellCommand $ take 10 as
runChunks $ drop 10 as
也做同样的事情(一次运行列表中的所有命令)。另一个具有相同结果的库:
import Control.Concurrent.Async
runChunks :: [String] -> IO ()
runChunks [] = return ()
runChunks as = do
ck <- mapM (async . execShellCommand) $ take 10 as
mapM_ wait ck
runChunks $ drop 10 as
我要么在这里没有掌握一个概念,在这种情况下,我非常感谢一个澄清的解释,或者我只是没有看到一个库函数可以达到我想要的效果;对于后者,一个例子将非常有帮助。非常感谢您。
【问题讨论】:
-
无关:您不应该导入
Internal模块。在这种情况下,您可以改为导入Data.List.Split。 -
查看此答案stackoverflow.com/a/29155440/1364288 了解另一种不涉及分块的方法。
标签: haskell asynchronous concurrency