使函数内联避免关闭?

时间:2009-12-29 13:13:54

标签: .net f# functional-programming

我正在阅读一篇博文: 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的情况下,速度并不会太大。

谢谢!

1 个答案:

答案 0 :(得分:6)

  

我们需要传入比较函数的指针。看起来   在C的情况下,速度不会太大。

如果将它与C ++ - std::sort的实现进行比较,它会发生。

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

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