我有一个n位“单词”列表
type BitWord = [Bool]
和一个从上到下存储单词的trie:
data Tree = Bs Tree Tree -- Bs (zero_bit) (one_bit)
| X -- incomplete word
| B -- final bit of word
我有一个功能:
seenPreviously :: BitWord -> Tree -> (Tree,Bool)
该函数逐步通过BitWord
中的位,同时通过Tree
下降到零位,反之亦然。我们返回一个新的树,其中BitWord
“合并在一起”,如果我们必须在某个时刻添加子树(即BitWord
已经不在trie中),则返回True,否则返回False。 p>
我将此函数映射到[BitWord]
,将树作为状态传递。
我的问题是:这可以从Control.Parallel提供的并行性中受益吗?如果是这样的话,我如何才能将懒惰和评价仅仅归结为弱头正常形式等?
我的直觉是,我可以在左侧分支中插入(实际构建一个子树),同时在右侧分支中执行相同的操作,作为两个独立的线程。类似的东西:
parallelMapSt :: [ BitWords ] -> Tree -> [Bool]
parallelMapSt [] _ = []
parallelMapSt (w:ws) t = let (b,t') = seenPreviously w t
bs = parralelMapSt ws t'
in t' `par` bs `pseq` (b:bs)
评估b
的线程依赖于一些先前引发的线程(属于BitWords
的线程与w
共享一些共同前缀),但不是全部,所以它似乎有机会在这里并行工作,但我真的不确定。
答案 0 :(得分:4)
在遍历树时看起来像是使用par
的很好的候选者......就像二叉树基准测试一样。尝试编写此类型的某些程序,并测量par
的效果。
答案 1 :(得分:4)
返回一个单词是否在trie中不必要地对您的程序进行顺序化。如果您确实需要此信息,则可能难以有效并行化。
但是,如果我们可以稍微改一下这个问题,那么插入的顺序和处理无关紧要,问题非常简单:
import Control.Parallel
data Tree = Bs Bool -- ^ is an empty word inserted here?
(Maybe Tree) -- ^ '0' subtree
(Maybe Tree) -- ^ '1' subtree
deriving Show
insertMany :: [[Bool]] -> Maybe Tree
insertMany [] = Nothing
insertMany xss = hasEnd `par` fs `par` ts `pseq` Just (Bs hasEnd fs ts)
where
hasEnd = any null xss
fs = insertMany [ xs | False : xs <- xss]
ts = insertMany [ xs | True : xs <- xss]
我目前没有多个核心,所以我无法对此进行测试,但它应该可以很好地扩展。我们基本上只用了几行就得到了一个并行基数 - 不是太破旧了!
答案 2 :(得分:1)
你为什么不试试看?用1个线程和几个线程执行程序的时间,看看是否存在差异。 Haskell中的Spark非常便宜,所以如果你创建了很多它们,不要担心。