Haskell 嵌套向量并行策略

标签 haskell vector nested parallel-processing

类似于this related question ,我想在向量上执行并行映射,但在我的例子中,我有一个嵌套向量,并且我似乎无法获得正确的评估。

这是我到目前为止所拥有的:

import qualified Data.Vector as V
import qualified Data.Vector.Unboxed as U
import Data.Vector.Strategies 
import Control.DeepSeq

main = do
  let res = genVVec 200 `using` parVector 2
  print res

genUVec :: Int -> U.Vector Int
genUVec n = U.map (ack 2) $ U.enumFromN n 75

genVVec :: Int -> V.Vector (U.Vector Int)
genVVec n = V.map genUVec $ V.enumFromN 0 n

ack :: Int -> Int -> Int
ack 0 n = n+1
ack m 0 = ack (m-1) 1
ack m n = ack (m-1) (ack m (n-1))

instance (NFData a, U.Unbox a) => NFData (U.Vector a) where
  rnf = rnf . U.toList

给出:

$ ./vectorPar +RTS -N8 -s >/dev/null
   SPARKS: 200 (17 converted, 183 pruned)
   Total time    1.37s  (  1.30s elapsed)
$ ./vectorPar +RTS -s >/dev/null
   SPARKS: 200 (0 converted, 200 pruned)
   Total time    1.25s  (  1.26s elapsed)

我还尝试修改 parVector 函数 in vector-strategies直接,但我的尝试是笨拙且无效的。

我意识到 REPA 是为嵌套工作负载而设计的,但这似乎是一个足够简单的问题,我宁愿不必重写大量代码。

最佳答案

注意:这里是矢量策略的有罪作者(这是一个非常小的标题,因为这只是一个我认为其他人会发现有用的黑客功能)。

您认为 parVector 是错误的,因为它允许在使用之前对 Spark 进行 GC 处理,这似乎是正确的。 SimonM 的建议意味着我必须精确地做我试图避免的事情,以一定的成本构建一个新的向量来代替旧的向量。知道这是必要的,没有理由不将 parVector 更改为更简单的定义:

parVector2 :: NFData a => Int -> Strategy (V.Vector a)
parVector2 n = liftM V.fromList . parListChunk n rdeepseq . V.toList

请注意,John L 给出的修复之所以有效,是因为它通过在收集发生之前强制进行计算来“击败”收集器。

我将更改矢量策略库,因此这是不必要的 - 使您的原始代码正常工作。不幸的是,这将产生上述构建新 Vector 的成本(通常很小)。

关于Haskell 嵌套向量并行策略,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/6750297/

相关文章:

haskell - -XStrict 在 GHC 中有什么作用吗?

haskell - 为什么管道定义内部功能

haskell - func::也许(Int) -> 也许(Int)

haskell - 是否可以在实例子句中使用 `let in`?

c++ - find() 在 C++ header 中不起作用

c++ - 获取指向 vector C++ 的指针

C++ vector 模板参数 1 无效

c - 嵌套 If..else - 错误输出,直接转到 C 编程语言中的最后一个 else

asp.net - 访问母版页中的祖 parent 内容占位符

ruby-on-rails - 如何在 Ruby on Rails 3 中以嵌套形式调用对象的方法?