Cabal似乎无法构建并行运行的可执行文件

时间:2018-07-15 21:54:42

标签: haskell parallel-processing cabal

我目前正在阅读《 Haskell中的并行和并发编程》一书,而我正试图让第一个示例在我的机器上运行,这实际上是一些数独解算器算法,该书说明了如何使用haskell在两个核心之间划分求解器的多次迭代。这是代码:

module Main where

import           Control.DeepSeq
import           Control.Monad
import           Control.Parallel.Strategies
import qualified Data.Maybe as M
import           Data.Monoid ((<>))
import           Sudoku
import           System.Environment

data ExecutionMode
  = ExecPar
  | ExecSeq

main :: IO ()
main = do
  execMode <- getExecMode
  filepath <- getFilepath
  attemptRun execMode filepath
  where
    attemptRun execMode filepath =
      case (execMode, filepath) of
        (Just mode, Just file) -> sudoku mode file
        (Nothing, _) -> putStrLn "Please provide valid execution mode: 'par' / 'seq'"
        _ -> putStrLn "Please choose a file, 1000 / 16000 / 49151"

    getExecMode =
      (parseExecMode <=< M.listToMaybe) <$> getArgs

    getFilepath =
      (parseFilepath <=< M.listToMaybe . drop 1) <$> getArgs

    parseExecMode "par" = Just ExecPar
    parseExecMode "seq" = Just ExecSeq
    parseExecMode _ = Nothing

    parseFilepath str =
      (\n -> "sudoku17." <> n <> ".txt") <$> case str of
        "1000" -> Just "1000"
        "16000" -> Just "16000"
        "49151" -> Just "49151"
        _ -> Nothing

sudoku :: ExecutionMode -> String -> IO ()
sudoku execMode filepath = determineMode
  where
    determineMode =
      case execMode of
        ExecPar -> runParallel
        ExecSeq -> runSequential

    runParallel = do
      (as, bs) <- (\p -> splitAt (length p `div` 2) p) . lines <$> readFile ("sudoku/data/" <> filepath)
      print . length . filter M.isJust . runEval $ do
        as' <- rpar (force (map solve as))
        bs' <- rpar (force (map solve bs))
        _ <- rseq as'
        _ <- rseq bs'
        return (as' ++ bs')
      return ()

    runSequential = do
      puzzles <- lines <$> readFile ("sudoku/data/" <> filepath)
      print . length . filter M.isJust $ solve <$> puzzles
      return ()

算法solve来自Sudoku,该算法已从书中提炼出来,我很确定这对我的问题无关紧要。

因此,当我尝试使用cabal运行此代码时,会发生以下情况:

λ time cabal new-run sudoku par 16000 +RTS -N2
Up to date
16000
cabal new-run sudoku par 16000 +RTS -N2  17.82s user 0.15s system 100% cpu 17.954 total

然后并行:

λ time cabal new-run sudoku seq 16000 +RTS -N2
Up to date
16000
cabal new-run sudoku seq 16000 +RTS -N2  17.50s user 0.07s system 100% cpu 17.546 total

请注意,时间没有差异。当我使用ghc进行编译时,会发生以下情况:

λ ghc -O2 sudoku/Main.hs -threaded -v src/Sudoku.hs
λ time sudoku/Main par 16000 +RTS -N2
16000
sudoku/Main par 16000 +RTS -N2  19.59s user 0.28s system 198% cpu 10.034 total

使用seq标志,它会花费更长的时间,就像您期望的那样:

λ time sudoku/Main seq 16000 +RTS -N2
16000
sudoku/Main seq 16000 +RTS -N2  19.99s user 1.44s system 109% cpu 19.557 total

这是我的.cabal文件:

build-type:          Simple
extra-source-files:  ChangeLog.md
cabal-version:       >=1.10

library
  build-depends:       base >=4.8 && <4.9
                     , array
                     , time
  hs-source-dirs:      src
  exposed-modules:     Sudoku
  default-language:    Haskell2010

executable sudoku
  main-is:             Main.hs
  ghc-options:         -O2 -Wall -Werror -threaded
  build-depends:       base >=4.8 && <4.9
                     , deepseq
                     , parallel
                     , parallel-and-concurrent-programming-in-haskell
  hs-source-dirs:      sudoku
  default-language:    Haskell2010

我在这里错过了什么吗?这是阴谋集团的正确行为吗?还是在ghc-optionsghc之间出了问题?

1 个答案:

答案 0 :(得分:4)

也许尝试运行:

time cabal new-run sudoku -- par 16000 +RTS -N2

--通常说“这些标志属于已执行的程序”。