如何使用Repa或Accelerate处理无限序列?

时间:2013-11-25 10:16:19

标签: haskell

我刚刚开始学习Haskell,我的问题可能很简单,所以请抱歉打扰。

所以,想象一下我有一个真正的无限数据源(例如stdin),我想使用Repa或Accelerate的并行工具来处理数据。它们都使用数组(有限数据结构)。在我看来,我将在代码中处理数组序列,但我真的不知道该怎么做,然后我需要一个数组中的一些数据和下一个数据来计算某些数据。

所以,我的意思是,如何为所有输入计算y = phase(a[i] * conj a[i+1]),其中a是无限的复数流。

2 个答案:

答案 0 :(得分:3)

正如您所提到的,

修复和加速都设计用于固定大小的数组和矩阵。这些是面向批处理的算法,它们基于许多优化,仅在使用固定内存位时才可用。

对于"无限"您需要数据流(或#34;在线")算法的数据。您描述的那个是可流式的,因为它只需要一个有限的窗口。您可以将流式算法转换为大量的小批量步骤,方法是使用Repa为流入的每对输入(a[i], a[i+1])计算相位,但由于大量的装箱,您可能会失去速度和复制需要将每个小块移动到连续的内存阵列。

要进行比较,您可以使用类似pipes的内容生成快速流式算法。

import Pipes
import Data.Complex

type ComplexPair = (Complex Double, Complex Double)

pairOff :: Monad m => Pipe a (a, a) m r
pairOff = await >>= forever . go where
  go x = await >>= \y -> yield (x, y)

compute :: Monad m => Pipe ComplexPair Double m r
compute = do
  (ai, ai1) <- await
  yield (phase $ ai * conjugate ai1)

run :: Monad m => Pipe (Complex Double) Double m r
run = pairOff >-> compute

然后run可以由无限流输入源提供,并转储到处理管道的下一步。这些来源可以是Monadic,如果是m ~ Identity,则可以是纯粹的。

答案 1 :(得分:3)

据我所知,您不能直接使用无限数据流来修复或加速。它设计用于向量,这是一种不同类型的数据结构。有很多方法可以解决这个问题:

  1. 读入固定数量的值,用它构造一个向量,执行计算,再次向下游推送值,一次迭代处理数据块。您必须弄清楚您想要的块大小,但它会在计算过程中为您提供最佳性能。不幸的是,这意味着你将失去所有那些读取构造步骤的效率。事实上,这将是我最担心的并行化步骤,因为您可以在处理上一个块时执行这些步骤。

  2. 忘记使用矢量库并转到管道库。它旨在处理恒定内存中的数据流,并获得相当不错的性能。使用pipes-concurrency包,您可以编写一个流处理器来读取数据并并行处理它。您将无法获得向量的效率,但在使用最少的RAM时,它将更容易有效地处理您的无限数据流。

  3. 首先使用列表实现它,懒惰地处理每个元素并使用常规的Haskell函数来执行此操作。你不会从速度或内存使用中获益,但它很容易编写。一旦你掌握了这个概念,就可以决定是否需要向量或流的效率,然后运行基准测试工具来确定你的瓶颈在哪里进行优化。

  4. 就个人而言,我会从2.或3.开始,然后弄清楚我的程序是否足够慢以保证使用向量。可能你可以从矢量中获得额外的性能,但除非你使用的是GPU,否则这种情况不太可能。