【问题标题】:making functions inline avoids closure?使函数内联避免关闭?
【发布时间】:2013-01-08 03:43:22
【问题描述】:

我正在阅读一篇博文: http://flyingfrogblog.blogspot.com/2009/07/ocaml-vs-f-burrows-wheeler.html

Burrow Wheeler 压缩算法的简单实现:

# compare two strings str[i..end,0..i-1] and str[j..end,0..j-1]
let cmp (str: _ array) i j =
  let rec cmp i j =
    if i=str.Length then 1 else
      if j=str.Length then -1 else
        let c = compare str.[i] str.[j] in
        if c<>0 then c else
          cmp (i+1) (j+1)
  cmp i j
# sort n strings
let bwt (str: byte array) =
  let n = str.Length
  let a = Array.init n (fun i -> i)
  Array.sortInPlaceWith (cmp str) a
  Array.init n (fun i -> str.[(a.[i] + n - 1) % n])

这个实现看起来很高效,但实际上很慢,因为排序Array.sortInPlaceWith (cmp str) a 使用了一个闭包函数(cmp str),并且调用它的次数太多(平均为O(n log n))!

通过将排序算法内联和比较函数内联,速度快。

我的问题是,内联函数是否意味着看似闭包的调用不再是闭包?

我在想的另一件事是 C 中的函数指针。当我们使用 qsort 时:

void qsort ( void * base, size_t num, size_t size, int ( * comparator ) ( const void *, const void * ) );

我们需要传入一个比较函数的指针。似乎在 C 的情况下,速度并没有太多。

谢谢!

【问题讨论】:

    标签: .net f# functional-programming


    【解决方案1】:

    我们需要传入一个比较函数的指针。看起来 在 C 的情况下,速度不会很糟糕。

    如果您将它与 std::sort 的 C++ 实现进行比较,它确实如此。

    您可以将 C++ 版本视为上面提到的内联代码。通过使用模板,您不需要运行时间接调用函数指针,而是编译器可以在编译时直接插入和优化给定的比较谓词。

    在您的上述 F# 代码的情况下,第一个实现将要求编译器生成一个在运行时通过间接调用的闭包对象,而内联版本不需要间接,因为它的实现在编译时是已知的。 (但由于 .NET 的 JIT 编译器甚至可以在运行时进行这样的优化,我从没想过差别会这么大)

    【讨论】:

    • 谢谢。我对 qsort 和 std::sort 有很多经验。排序更快,但只有一点点。 Jon Harrop 说他的内联版本快了大约 100 倍。也许那是 F# 编译器的旧版本,它仍在不断发展。
    猜你喜欢
    • 2013-10-03
    • 2022-01-25
    • 2011-03-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多