Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/performance/5.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Multithreading 为什么这个Haskell程序在使用线程编译时会执行奇怪的操作?_Multithreading_Performance_Haskell_Parallel Processing_Ghc - Fatal编程技术网

Multithreading 为什么这个Haskell程序在使用线程编译时会执行奇怪的操作?

Multithreading 为什么这个Haskell程序在使用线程编译时会执行奇怪的操作?,multithreading,performance,haskell,parallel-processing,ghc,Multithreading,Performance,Haskell,Parallel Processing,Ghc,考虑下面的玩具程序,该程序通过对字典单词应用字符替换来强制进行密码哈希。字典按顺序或并行遍历,编译时由PARMAP符号触发 import qualified Control.Parallel.Strategies as Strat import qualified Crypto.Hash.SHA256 as SHA256 import qualified Data.ByteString as BS import qualified Data.ByteString.Base16 as BS.Bas

考虑下面的玩具程序,该程序通过对字典单词应用字符替换来强制进行密码哈希。字典按顺序或并行遍历,编译时由
PARMAP
符号触发

import qualified Control.Parallel.Strategies as Strat
import qualified Crypto.Hash.SHA256 as SHA256
import qualified Data.ByteString as BS
import qualified Data.ByteString.Base16 as BS.Base16
import qualified Data.ByteString.Char8 as BS.Char8
import Data.Char (isLower, toUpper)
import Data.Maybe (listToMaybe)

variants :: String -> [String]
variants "" = [""]
variants (c:s) = [c':s' | s' <- variants s, c' <- subst c]
  where subst 'a' = "aA@"
        subst 'e' = "eE3"
        subst 'i' = "iI1"
        subst 'l' = "lL1"
        subst 'o' = "oO0"
        subst 's' = "sS$5"
        subst 'z' = "zZ2"
        subst x | isLower x = [x, toUpper x]
        subst x = [x]

myMap :: (a -> [a]) -> [a] -> [[a]]
#ifdef PARMAP
myMap = Strat.parMap (Strat.evalList Strat.rseq)
#else
myMap = map
#endif

bruteForce :: [String] -> BS.ByteString -> Maybe String
bruteForce dictionary hash = listToMaybe $ concat $ myMap match dictionary
  where match word = [var | var <- variants word,
                      SHA256.hash (BS.Char8.pack var) == hash]

main :: IO ()
main = do
  dictionary <- lines `fmap` (readFile "dictionary.txt")
  hash <- (fst . BS.Base16.decode . BS.Char8.pack) `fmap` getLine
  case bruteForce dictionary hash of
    Just preimage -> putStrLn preimage
    Nothing -> return ()
为了运行这个程序,我制作了一个小词典,并从中提取最后一个单词

$ shuf -n 300 /usr/share/dict/american-english >dictionary.txt
$ tail -n 1 dictionary.txt 
desalinates
$ echo -n 'De$aL1n@teS' | sha256sum
3c76d2487f8094a8bf4cbb9e7de7624fab48c3d4f82112cb150b35b9a1cb9072  -
我在2核CPU上运行这个。此计算机上没有运行其他CPU密集型进程

顺序映射版本按预期执行

$ TIMEFORMAT='real %R   user %U   sys %S'
$ time ./brute.seq <<<3c76d2487f8094a8bf4cbb9e7de7624fab48c3d4f82112cb150b35b9a1cb9072
De$aL1n@teS
real 39.797   user 39.574   sys 0.156
$ time ./brute.seq+th <<<3c76d2487f8094a8bf4cbb9e7de7624fab48c3d4f82112cb150b35b9a1cb9072
De$aL1n@teS
real 44.313   user 44.159   sys 0.088
$ time ./brute.seq+th +RTS -N <<<3c76d2487f8094a8bf4cbb9e7de7624fab48c3d4f82112cb150b35b9a1cb9072
De$aL1n@teS
real 44.990   user 44.835   sys 0.876
当我将并行映射与
线程化的
结合起来,但还没有使用两个内核时,事情开始变得奇怪

$ time ./brute.par+th <<<3c76d2487f8094a8bf4cbb9e7de7624fab48c3d4f82112cb150b35b9a1cb9072
De$aL1n@teS
real 58.636   user 73.661   sys 17.717
现在我有两个可能相关的问题

  • 为什么单核
    brute.par+th
    比单核
    brute.par
    慢那么多?它在这些线程中做什么?它在内核模式下花了17秒做什么
  • 为什么2核
    brute.par+th
    的性能变化如此之大,而不是1核
    brute.par+th
    的两倍
  • 我正在使用GHC 7.4.1和parallel-3.2.0.2。我知道我可能应该使用更新的版本,但这是我目前手头上的

    我尝试使用
    -rtsopts
    编译,并使用
    +RTS-qg
    禁用线程化GC,但没有效果


    我尝试了ThreadScope,但它进行了疯狂的交换,甚至在我使用更小的字典时也无法加载事件日志。

    意外的性能可以通过“Crypto.Hash.SHA256”调用不安全的FFI来解释。GHC不知道在调用此代码期间不会阻止其他Haskell线程。如果PAR产生的线程被GHC阻塞,这将导致程序中的大量争用,导致长时间运行和不一致的运行时间结果。

    改写为<代码> BS。这解决了第1个问题:如果没有
    +RTS-N
    ,所有4个版本现在都具有相同的性能。至于第2个版本,我现在注意到,重复运行时,运行时间从T增加到~2T,然后在CPU冷却时,实际下降到T。所以,也许这不是Haskell的问题,谢谢。如果明天没有人提出更好的答案,我会接受这个答案。在另一台机器上进行了尝试,运行时间稳定了(虽然在4个内核的情况下,加速比不到2倍,但我想这是另一个问题)。您可能想尝试编写用于处理更大事件日志的版本。
    $ time ./brute.par <<<3c76d2487f8094a8bf4cbb9e7de7624fab48c3d4f82112cb150b35b9a1cb9072
    De$aL1n@teS
    real 39.847   user 39.742   sys 0.056
    
    $ time ./brute.par+th <<<3c76d2487f8094a8bf4cbb9e7de7624fab48c3d4f82112cb150b35b9a1cb9072
    De$aL1n@teS
    real 58.636   user 73.661   sys 17.717
    
    $ time ./brute.par+th +RTS -N <<<3c76d2487f8094a8bf4cbb9e7de7624fab48c3d4f82112cb150b35b9a1cb9072
    De$aL1n@teS
    real 28.589   user 51.615   sys 2.304
    $ time ./brute.par+th +RTS -N <<<3c76d2487f8094a8bf4cbb9e7de7624fab48c3d4f82112cb150b35b9a1cb9072
    De$aL1n@teS
    real 59.149   user 106.255   sys 4.664
    $ time ./brute.par+th +RTS -N <<<3c76d2487f8094a8bf4cbb9e7de7624fab48c3d4f82112cb150b35b9a1cb9072
    De$aL1n@teS
    real 49.428   user 87.193   sys 3.816