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

Haskell 如何使用Repa或Accelerate处理无限序列?,haskell,Haskell,我刚刚开始学习Haskell,我的问题可能很琐碎,请原谅打扰 所以,假设我有一个真正的无限数据源(例如stdin),我想使用Repa或Accelerate的并行工具来处理数据。它们都使用数组(有限数据结构)。在我看来,这将在我的代码中处理数组序列,但我真的不知道该怎么做,然后我需要从一个数组和下一个数组中获得一些数据来计算一些东西 因此,我的意思是,我如何计算所有输入的y=phase(a[I]*conj a[I+1]),其中a是无限的复数流。Repa和Accelerate,正如您所提到的,都是为

我刚刚开始学习Haskell,我的问题可能很琐碎,请原谅打扰

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


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

Repa和Accelerate,正如您所提到的,都是为固定大小的数组和矩阵设计的。这些是面向批处理的算法,它们基于许多优化,只有在使用固定内存位时才可用

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

要进行比较,您可以使用类似于
管道的方法来生成快速流式算法

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
导入管道
导入数据。复杂
类型ComplexPair=(复数双精度,复数双精度)
pairOff::Monad m=>管道a(a,a)m r
等待>>=永远。去哪里
go x=等待>>=\y->收益率(x,y)
compute::Monad m=>Pipe ComplexPair Double m r
计算=do
(ai,ai1)管道(复合双)双m r
运行=pairOff>->计算

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

据我所知,您不能使用Repa或直接使用无限的数据流进行加速。它被设计为对向量进行操作,向量是一种不同的数据结构。有很多方法可以解决这个问题,您可以选择以下几种方法:

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

  • 忘记使用向量库,转到管道库。它被设计用于在恒定内存中处理数据流,并获得相当好的性能。使用
    pipes concurrency
    包,您可以编写一个流处理器来读取数据并并行处理。您将没有向量的效率,但在使用最小RAM的情况下更容易有效地处理无限的数据流

  • 首先用列表实现它,惰性地处理每个元素,并使用常规的Haskell函数来实现。您将无法获得速度或内存使用的好处,但它很容易编写。一旦你有了这个概念,你可以决定你是否需要向量或流的效率,然后运行一个基准测试工具来确定你的瓶颈在哪里,然后再尝试优化


  • 就我个人而言,我会从2开始。或者3.,然后确定我的程序是否足够慢,可以使用向量。也许你可以从vectors中获得额外的性能,但除非你使用GPU,否则这是不可能的。

    这有点讽刺,因为在引擎盖下,
    vector
    库确实拥有无限有效流的机制,因为它的流融合表示(请参阅)基本上相当于
    管道
    中的
    生产者
    。只是库没有提供好的工具来直接处理这种类型,而是更愿意将其作为实现细节隐藏起来。@GabrielGonzalez有趣的是,我以前从未发现过这一点。Repa和/或Accelerate是否具有此功能?我快速查看了每个模块的模块列表,但没有看到任何可能包含它的内容。@HounD对于实现1,实际上可以使用Repa和的组合,前者进行处理,后者进行流式处理。基本思想是使用管道读入一大块数据,然后用这些值构造一个Repa数组。然后,它们可以通过管道输送到你的数字运算消费者,然后再通过管道输送到下一个阶段。今天晚些时候我可以举个例子。如果你还在为Haskell的部分内容苦苦挣扎,我还建议你学习Hs和真实世界Hs(谷歌链接,没有空间)。@HounD-See获取代码和我的建议comments@Hound您可以从阅读开始,它描述了向量库如何尝试融合中间向量。