【问题标题】:QSem doesn't seem to block threadsQSem 似乎没有阻塞线程
【发布时间】:2023-03-11 00:13:01
【问题描述】:
我正在编写一个简单的脚本来使用Shelly 库并行运行一堆任务,但我想限制任何时候运行的最大任务数。该脚本获取一个文件,每行都有一个输入,并为该输入运行一个任务。文件中有几百个输入,我想一次限制为大约 16 个进程。
当前脚本实际上限制为 1(很好地尝试)使用初始计数为 1 的 QSem。但我似乎遗漏了一些东西,因为当我在具有 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, file] <- liftIO $ getArgs
内容 <- readfile $ fromText $ LT.pack 文件
-- 为每一行输入运行一个后台进程。
结果 <- forM (LT.lines 内容) $ \line -> bkGrnd $ do
runStdin <command> <arguments>
LiftIO $mapM_takeMVar 结果
【问题讨论】:
-
我不了解雪莉,但从您的代码看来,bkGrnd 的每个应用程序都有自己的新信号量,初始化为 1。您应该先创建一个,然后将同一个信号量传递给每次通话。
标签:
haskell
semaphore
shelly