Haskell 部分同时生效的行动清单

Haskell 部分同时生效的行动清单,haskell,asynchronous,concurrency,Haskell,Asynchronous,Concurrency,我有一个表示shell命令的字符串列表,我希望一次并发执行10个。这是我在Haskell中第一次真正尝试并发编程,我遇到了一些麻烦 我的想法是将列表分为十个元素的子列表,然后mapM一个函数,该函数同时生成十个命令中的每一个,等待每个命令完成后再进入下一组十个。然而,我使用/采取的每一种不同的库/方法似乎只是同时启动列表中的每个命令 假设我有最简单的函数来执行shell命令: import System.Process execShellCommand :: String ->

我有一个表示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
一次执行列表中的所有命令(我尝试使用conductor.Process中的
waitFor
函数,结果类似)。让我们更仔细地考虑一下,重新定义函数
execShellCommand
,以使用
控件。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
导入控制。并发
EXECSHELL命令::字符串->IO()
execShellCommand cmd=do
m IO()
runChunks[]=返回()
runchunk as=do

ck我有点好奇你用
waitFor
尝试了什么。这是我的第一次尝试:

import System.Process

commands = ["./demo.sh " ++ show n | n <- [1..10]]

chunksOf _ [] = []
chunksOf n xs = take n xs : chunksOf n (drop n xs)

spawn cmd = do
  (_,_,_,proc) <- createProcess (shell cmd)
  return proc

spawnAndAwaitGroup cmds = do
  procs <- mapM spawn cmds
  mapM_ waitForProcess procs

main = do
  mapM_ spawnAndAwaitGroup (chunksOf 3 commands)
输出:

2 starting
1 starting
3 starting
3 ending
1 ending
2 ending
4 starting
5 starting
6 starting
4 ending
5 ending
6 ending
7 starting
8 starting
9 starting
7 ending
8 ending
9 ending
10 starting
10 ending
值得注意的是,这是一个纯粹的顺序程序,在Haskell级别上不是并发的。它相当于此shell脚本:

./demo.sh 1 &
./demo.sh 2 &
./demo.sh 3 &
wait
./demo.sh 4 &
./demo.sh 5 &
./demo.sh 6 &
wait
./demo.sh 7 &
./demo.sh 8 &
./demo.sh 9 &
wait
./demo.sh 10 &
wait

所有并发行为都发生在操作系统级别,即派生进程的交互中

无关:不应导入
内部
模块。在这种情况下,您可以导入
数据.List.Split
。有关不涉及分块的另一种方法,请参阅此答案。
2 starting
1 starting
3 starting
3 ending
1 ending
2 ending
4 starting
5 starting
6 starting
4 ending
5 ending
6 ending
7 starting
8 starting
9 starting
7 ending
8 ending
9 ending
10 starting
10 ending
./demo.sh 1 &
./demo.sh 2 &
./demo.sh 3 &
wait
./demo.sh 4 &
./demo.sh 5 &
./demo.sh 6 &
wait
./demo.sh 7 &
./demo.sh 8 &
./demo.sh 9 &
wait
./demo.sh 10 &
wait