F#性能问题:编译器在做什么?

时间:2010-05-31 20:38:22

标签: f# compilation

引用此代码:F# Static Member Type Constraints

为什么,例如,

let gL = G_of 1L
[1L..100000L] |> List.map (fun n -> factorize gL n)

显着慢于

[1L..100000L] |> List.map (fun n -> factorize (G_of 1L) n)

通过查看Reflector,我可以看到编译器正在以非常不同的方式处理每一个,但是有太多的东西让我破译本质的区别。天真地我认为前者会比后者表现更好,因为gL是预先计算的,而G_of 1L必须计算100,000次(至少看起来是这样)。

[修改

看起来这可能是F#2.0 / .NET 2.0 / Release-mode的错误,请参阅@ gradbot的回答和讨论。

1 个答案:

答案 0 :(得分:1)

Reflector显示test2()变为4个类,而test1()变成了两个类。这只发生在调试模式下。 Reflector在发布模式下显示相同的代码(每个类一个)。不幸的是,当我尝试在C#中查看源代码时,Reflector崩溃了,而且IL很长。

let test1() =
    let gL = G_of 1L
    [1L..1000000L] |> List.map (fun n -> factorize gL n)

let test2() =
    [1L..1000000L] |> List.map (fun n -> factorize (G_of 1L) n)

快速基准。

let sw = Stopwatch.StartNew()
test1() |> ignore
sw.Stop()
Console.WriteLine("test1 {0}ms", sw.ElapsedMilliseconds)

let sw2 = Stopwatch.StartNew()
test2() |> ignore
sw2.Stop()
Console.WriteLine("test2 {0}ms", sw2.ElapsedMilliseconds)

基准测试在I7 950 @ 3368Mhz,Windows 7 64位,VS2010 F#2.0上运行

x86调试
test1 8216ms
test2 8237ms

x86发布
test1 6654ms
test2 6680ms

x64调试
test1 10304ms
test2 10348ms

x64发布
test1 8858ms
test2 8977ms

这是完整的代码。

open System
open System.Diagnostics

let inline zero_of (target:'a) : 'a = LanguagePrimitives.GenericZero<'a>
let inline one_of (target:'a) : 'a = LanguagePrimitives.GenericOne<'a>
let inline two_of (target:'a) : 'a = one_of(target) + one_of(target)
let inline three_of (target:'a) : 'a = two_of(target) + one_of(target)
let inline negone_of (target:'a) : 'a = zero_of(target) - one_of(target)

let inline any_of (target:'a) (x:int) : 'a =
    let one:'a = one_of target
    let zero:'a = zero_of target
    let xu = if x > 0 then 1 else -1
    let gu:'a = if x > 0 then one else zero-one

    let rec get i g = 
        if i = x then g
        else get (i+xu) (g+gu)
    get 0 zero 

type G<'a> = {
    negone:'a
    zero:'a
    one:'a
    two:'a
    three:'a
    any: int -> 'a
}    

let inline G_of (target:'a) : (G<'a>) = {
    zero = zero_of target
    one = one_of target
    two = two_of target
    three = three_of target
    negone = negone_of target
    any = any_of target
}

let inline factorizeG n = 
    let g = G_of n
    let rec factorize n j flist =  
        if n = g.one then flist 
        elif n % j = g.zero then factorize (n/j) j (j::flist) 
        else factorize n (j + g.one) (flist) 
    factorize n g.two []

let inline factorize (g:G<'a>) n =   //'
    let rec factorize n j flist =  
        if n = g.one then flist 
        elif n % j = g.zero then factorize (n/j) j (j::flist) 
        else factorize n (j + g.one) (flist) 
    factorize n g.two []

let test1() =
    let gL = G_of 1L
    [1L..100000L] |> List.map (fun n -> factorize gL n)

let test2() =
    [1L..100000L] |> List.map (fun n -> factorize (G_of 1L) n)

let sw2 = Stopwatch.StartNew()
test1() |> ignore
sw2.Stop()
Console.WriteLine("test1 {0}ms", sw2.ElapsedMilliseconds)

let sw = Stopwatch.StartNew()
test2() |> ignore
sw.Stop()
Console.WriteLine("test2 {0}ms", sw.ElapsedMilliseconds)

Console.ReadLine() |> ignore