我正在编写一个简单的脚本来使用Shelly库并行运行一堆任务,但我想限制任何时候运行的最大任务数。该脚本获取一个文件,每行都有一个输入,并为该输入运行一个任务。文件中有几百个输入,我想一次限制为大约 16 个进程。
当前脚本实际上使用初始计数为 1 的 QSem 限制为 1(很好地尝试)。我似乎遗漏了一些东西,因为当我在具有 4 个输入的测试文件上运行时,我看到了这个:
开始 开始 开始 开始 完毕 完毕 完毕 完毕
所以线程并没有像我期望的那样阻塞在 QSem 上,它们都是同时运行的。我什至已经实现了我自己的信号量MVar,TVar而且都没有按我预期的方式工作。我显然错过了一些基本的东西,但是什么?我还尝试编译代码并将其作为二进制文件运行。
#!/usr/bin/env runhaskell
{-# LANGUAGE TemplateHaskell, QuasiQuotes, DeriveDataTypeable, OverloadedStrings #-}
进口雪莉
导入前奏隐藏(FilePath)
导入 Text.Shakespeare.Text (lt)
导入合格的 Data.Text.Lazy 作为 LT
导入 Control.Monad (forM)
导入 System.Environment (getArgs)
将合格的 Control.Concurrent.QSem 导入为 QSem
导入 Control.Concurrent (forkIO, MVar, putMVar, newEmptyMVar, takeMVar)
-- 定义最大并发进程数
maxProcesses :: IO QSem.QSem
maxProcesses = QSem.newQSem 1
bkGrnd :: ShIO a -> ShIO (MVar a)
bkGrnd 过程 = 做
mvar <- liftIO newEmptyMVar
_ <- liftIO $ forkIO $ 做
-- 阻塞直到有空闲进程
sem <- maxProcesses
QSem.waitQSem sem
putStrLn "开始"
-- 运行shell命令
结果 <- shelly $ 静默处理
liftIO $ putMVar mvar 结果
putStrLn “完成”
-- 表示这个过程已经完成并且另一个可以运行。
QSem.signalQSem sem
返回 mvar
主::IO()
main = shelly $ 默默地 $ do
[img, 文件] <- liftIO $ getArgs
内容 <- readfile $ fromText $ LT.pack 文件
-- 为每一行输入运行一个后台进程。
结果 <- forM (LT.lines 内容) $ \line -> bkGrnd $ do
runStdin <命令> <参数>
LiftIO $mapM_takeMVar 结果