4

Shellyライブラリを使用して一連のタスクを並行して実行する簡単なスクリプトを作成していますが、一度に実行するタスクの最大数を制限したいと思います。スクリプトは、各行に入力があるファイルを取得し、その入力に対してタスクを実行します。ファイルには数百の入力があり、一度に約16プロセスに制限したいと思います。

現在のスクリプトは、初期カウントが1のQSemを使用して、実際には1に制限されています(うまく試行されます)。ただし、4つの入力を持つテストファイルで実行すると、次のように表示されます。

起動
起動
起動
起動
終わり
終わり
終わり
終わり

したがって、スレッドはQSemでブロックされていません。予想どおり、すべて同時に実行されています。私は自分のセマフォを実装するところまで行ってMVarおりTVar、どちらも期待どおりに機能しませんでした。私は明らかに基本的な何かが欠けていますが、何ですか?また、コードをコンパイルしてバイナリとして実行してみました。

#!/ usr / bin / env runhaskell
{-#言語TemplateHaskell、QuasiQuotes、DeriveDataTypeable、OverloadedStrings#-}

Shellyをインポートする
プレリュード非表示のインポート(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 proc = do
  mvar <-liftIO newEmptyMVar
  _ <-liftIO $ forkIO $ do
    -空きプロセスができるまでブロックします
    sem <-maxProcesses
    QSem.waitQSem sem
    putStrLn「開始中」
    -シェルコマンドを実行します
    結果<-shelly$サイレントproc
    liftIO $putMVarmvar結果
    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の結果
4

3 に答える 3

6

コメントで述べたように、各呼び出しbkGrndは独自のセマフォンを作成し、すべてのスレッドが待機せずに続行できるようにします。代わりに、セマフォが で作成され、main毎回 に渡されるこのようなものを試してみbkGrndます。

bkGrnd :: QSem.QSem -> ShIO a -> ShIO (MVar a)
bkGrnd sem proc = do
  mvar <- liftIO newEmptyMVar
  _ <- liftIO $ forkIO $ do
    -- Block until there are free processes
    QSem.waitQSem sem
    --
    -- code continues as before
    --

main :: IO ()
main = shelly $ silently $ do
    [img, file] <- liftIO $ getArgs
    contents <- readfile $ fromText $ LT.pack file
    sem <- maxProcesses
    -- Run a backgrounded process for each line of input.
    results <- forM (LT.lines contents) $ \line -> bkGrnd sem $ do
      runStdin <command> <arguments>
    liftIO $ mapM_ takeMVar results
于 2012-04-04T16:23:17.720 に答える
4

答えはありますが、追加する必要があります。killThread または非同期スレッドの死が可能である場合、QSem と QSemN はスレッドセーフではありません。

私のバグレポートとパッチはGHC trac ticket #3160です。修正されたコードは、モジュール Control.Concurrent.MSem、MSemN、MSampleVar、およびボーナス FairRWLock を備えたSafeSemaphoreと呼ばれる新しいライブラリとして利用できます。

于 2012-04-05T08:24:43.820 に答える
0

良くないですか

bkGrnd sem proc = do
  QSem.waitQSem sem
  mvar <- liftIO newEmptyMVar
  _ <- liftIO $ forkIO $ do
  ...

forkIOセマフォを取得するまではそうではありませんか?

于 2013-08-25T02:08:01.060 に答える