【问题标题】:What is the standard OCaml data structure with fastest iteration?迭代速度最快的标准 OCaml 数据结构是什么?
【发布时间】:2010-01-05 15:12:26
【问题描述】:

我正在寻找一个通过封装元素提供最快无序迭代的容器。换句话说,“一次添加,多次迭代”。

OCaml 的标准模块中是否有一个速度足够快(以至于进一步优化它是无用的)?还是某种第三方 GPL 就绪的?

AFAIK 只有一个 OCaml 编译器,所以快速的概念或多或少很清楚......

...但是在我看到几个答案之后,它似乎不是。当然,有很多数据结构允许通过大小为 n 的容器进行 O(n) 迭代。但我要解决的任务就是其中之一,其中 O(n) 和 O(2n) 之间的差异很重要 ;-)。

我还看到数组和列表提供了关于添加元素顺序的不必要信息,我不需要这些信息。也许在“功能世界”中存在可以用这些信息换取一点迭代速度的数据结构。

在 C 语言中,我会直接选择一个普通数组。问题是,我应该在 OCaml 中选择什么?

【问题讨论】:

  • 1) 为了迂腐,O(n) 和 O(2n) 之间没有区别。你说的是常数因素。 2) 为元素选择任意顺序并对其进行修复,如在数组或列表中,正是您优化迭代的方式。您希望如何改进“增加索引/跟随指针,从内存中获取”以提高迭代速度?
  • 1) 是的,我说的是常数因素,因为我正在优化瓶颈; 2) 我不知道如何改进,但 it 是 Array 和 List 模块的工作方式吗?数组没有(虽然它可能已知)占用连续的内存。列表需要指针取消引用(慢?)。我仍然有疑问。
  • @Pavel:克里斯的意思是你在滥用大 O 表示法。他并不是说您不应该关心常数因子,只是说您在引用它们时应该更清楚地使用数学符号。
  • @bcat,为什么这么严重? ;-) 我的意思是,我假设每个阅读 [ocaml] 标签中的问题的人都知道它的含义并且可以发现笑话,即使它们不太好:-\

标签: performance data-structures ocaml


【解决方案1】:

你不可能比内置数组和列表做得更好,因为它们是用 C 手工编码的,除非你绑定到你自己的迭代器的本机实现。数组的行为与 C 中的数组几乎完全相同(一个连续分配的内存块,包含一系列元素值),可能由于装箱而带有一些额外的指针间接。列表完全按照您的期望实现:作为具有值和“下一个”指针的单元格。数组将为您提供未装箱类型的最佳位置(尤其是 floats,它具有超级特殊的未装箱实现)。

有关数组和列表实现的信息,请参阅 OCaml 源代码中的 Section 18.3 of the OCaml manual 和文件 byterun/mlvalues.hbyterun/array.cbyterun/alloc.c

来自提问者:确实,Array 似乎是最快的解决方案。然而,它仅比List 高出 7%。可能是因为数组元素的类型不够简单:它是代数类型。正如预期的那样,Hashtbl 的表现差了 4 倍。

所以,我会选择Array,我会接受这个。不错。

【讨论】:

  • 这已经很老了,但由于某种原因,整个问题都被移到了顶部。请注意,列表不是用 C 手动编码的,它们被定义为通常的代数数据类型。为方便起见,取模一些语法糖,它只是type 'a list = Nil | Cons of 'a * 'a list。良好的性能是通过 OCaml 数据类型的良好表示选择来解释的,而不是专门化。不过,数组是内置的,并且确实具有更好的局部性。
【解决方案2】:

要确定,您必须测量。根据编译器可能生成的机器指令,我会尝试一个数组,然后是一个列表。

  • 访问数组元素需要边界检查、地址算术和加载

  • 访问列表头需要加载、空列表测试和已知编译时偏移的加载。

哪个更快的细节可能取决于您的应用程序以及您的机器上发生的其他情况。它们还取决于元素的类型;例如,如果它们是浮点数,ocamlopt 可能足够聪明,可以创建一个未装箱的数组,这将为您节省一定程度的间接性。

其他常见的数据结构,如哈希表或平衡树,通常需要您在某处分配一些上下文以跟踪您所在的位置。使用数组,跟踪只需要一个整数索引;使用列表,跟踪需要一个指针。我认为这在另一种数据结构中很难被击败。

最后请注意,OCaml 编译器可能只有一个,但它有两个后端:字节码和本机代码。如果您关心这种级别的性能,自然会使用本机代码ocamlopt 版本。对吧?

请进行测量并将结果编辑到您的问题中。

【讨论】:

    【解决方案3】:

    不要忘记Bigarrays,它们最接近 C 数组(只是一块平坦的内存),但不能包含任意 OCaml 值。还要考虑切换边界检查(unsafe_set/get)。当然,您应该先配置文件。

    【讨论】:

      【解决方案4】:

      数组 - 一个按顺序访问项目的线性内存块 - 最好地利用 CPU 的 L1 数据缓存。

      【讨论】:

      • 在 C 中确实如此……在 OCaml 中它仍然是最快的吗?
      • 如果它是未装箱的数据类型(例如整数),则数组值将存储在连续的内存块中。如果它是“盒装”数据类型(大多数是),那么它将是一个指针数组,因此您可能不会比列表获得太多。
      【解决方案5】:

      所有常见的数据结构都可以在 O(n) 时间内迭代,因此数据结构之间的差异只会是恒定的(而且很可能不显着)。

      至少列表和数组允许在没有显着开销的情况下进行迭代。我想不出这种速度不够快的情况。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2014-10-29
        • 2017-03-28
        • 2012-11-14
        • 2011-04-07
        相关资源
        最近更新 更多