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

Cabal seems unable to build executable that runs in parallel

我目前正在阅读 'Parallel and Concurrent Programming in 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

我是不是漏掉了什么?这是 cabal 的正确行为吗?或者 ghc-optionsghc 之间可能出了什么问题?

也许试试 运行:

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

--通常说"these flags belong to the executed program"。