2011-10-04 99 views
0

我正在與fsi.exe的兩個版本相同的F#代碼,我可以在我的FSharp-2.0.0.0找到相同的代碼安裝:巨大的性能差異運行F#的FSI 4.0.30319.1和2.0.0.0

C:\Program Files\FSharp-2.0.0.0\bin\fsi.exe - Microsoft (R) F# 2.0 Interactive build 2.0.0 

C:\Program Files\FSharp-2.0.0.0\v4.0\bin\fsi.exe - Microsoft (R) F# 2.0 Interactive build 4.0.30319.1 

我發現,在2.0.0.0版本上,相同的代碼運行速度快了三倍。這有意義嗎?有什麼搞砸了我的環境或可能的代碼?

順便提一下,我嘗試使用v4.0 build的原因是爲了能夠使用TPL並比較我的代碼的順序和並行實現。當我的並行執行比順序執行慢得多時,經過大量的頭痛之後,我意識到並行版本是在不同的fsi.exe下運行的,而當我意識到代碼的相同(順序)版本要慢得多在版本4.0下。

預先感謝任何幫助

IS

代碼:

module Options 

//Gaussian module is from http://fssnip.net/3g, by Tony Lee 
open Gaussian 

//The European Option type 
type EuropeanOption = 
     {StockCode: string 
     StockPrice: float 
     ExercisePrice: float 
     NoRiskReturn: float 
     Volatility: float 
     Time: float 
     } 

//Read one row from the file and return a European Option 
//File format is: 
//StockCode<TAB>StockPrice,ExercisePrice,NoRiskReturn,Volatility,Time 
let convertDataRow(line:string) = 
    let option = List.ofSeq(line.Split('\t')) 
    match option with 
    | code::data::_ -> 
     let dataValues = (data.Split(',')) 
     let euopt = {StockCode = code; 
        StockPrice = float (dataValues.[0]); 
        ExercisePrice = float (dataValues.[1]); 
        NoRiskReturn = float (dataValues.[2]); 
        Volatility = float (dataValues.[3]); 
        Time = float (dataValues.[4]) 
        } 
     euopt 
    | _ -> failwith "Incorrect Data Format" 

//Returns the future value of an option. 
//0 if excercise price is greater than the sum of the stock price and the calculated asset price at expiration. 
let futureValue sp ep nrr vol t = 
    //TODO: Is there no better way to get the value from a one-element sequence? 
    let assetPriceAtExpiration = sp+sp*nrr*t+sp*sqrt(t)*vol*(Gaussian.whiteNoise |> Seq.take 1 |> List.ofSeq |> List.max) 
    [0.0;assetPriceAtExpiration - ep] |> List.max 

//Sequence to hold the values generated by the MonteCarlo iterations 
//50,000 iterations is the minimum for a good aprox to the Black-Scholes equation 
let priceValues count sp ep nrr vol t = 
    seq { for i in 1..count 
      -> futureValue sp ep nrr vol t 
    } 

//Discount a future to a present value given the risk free rate and the time in years 
let discount value noriskreturn time = 
    value * exp(-1.0*noriskreturn*time) 

//Get the price for a European Option and a given number of Monte Carlo iterations (use numIters >= 50000) 
let priceOption europeanOption numIters = 
    let futureValuesSeq = priceValues numIters europeanOption.StockPrice europeanOption.ExercisePrice europeanOption.NoRiskReturn europeanOption.Volatility europeanOption.Time 
    //The simulated future value is just the average of all the MonteCarlo runs 
    let presentValue = discount (futureValuesSeq |> List.ofSeq |> List.average) europeanOption.NoRiskReturn europeanOption.Time 
    //Return a list of tuples with the stock code and the calculated present value 
    europeanOption.StockCode + "_to_" + string europeanOption.Time + "_years \t" + string presentValue 


module Program = 

    open Options 
    open System 
    open System.Diagnostics 
    open System.IO 

    //Write to a file 
    let writeFile path contentsArray = 
     File.WriteAllLines(path, contentsArray |> Array.ofList) 

    //TODO: This whole "method" is sooooo procedural.... is there a more functional way? 

    //Unique code for each run 
    //TODO: Something shorter, please 
    let runcode = string DateTime.Now.Month + "_" + string DateTime.Now.Day + "_" + string DateTime.Now.Hour + "_" + string DateTime.Now.Minute + "_" + string DateTime.Now.Second 

    let outputFile = @"C:\TMP\optionpricer_results_" + runcode + ".txt" 

    let statsfile = @"C:\TMP\optionpricer_stats_" + runcode + ".txt" 

    printf "Starting" 
    let mutable stats = ["Starting at: [" + string DateTime.Now + "]" ] 

    let stopWatch = Stopwatch.StartNew() 

    //Read the file 
    let lines = List.ofSeq(File.ReadAllLines(@"C:\tmp\9000.txt")) 

    ignore(stats <- "Read input file done at: [" + string stopWatch.Elapsed.TotalMilliseconds + "]"::stats) 
    printfn "%f" stopWatch.Elapsed.TotalMilliseconds 

    //Build the list of European Options 
    let options = lines |> List.map convertDataRow 

    ignore(stats <- ("Created Options done at: [" + string stopWatch.Elapsed.TotalMilliseconds + "]")::stats) 
    printfn "%f" stopWatch.Elapsed.TotalMilliseconds 

    //Calculate the option prices 
    let results = List.map (fun o -> priceOption o 50000) options 

    ignore(stats <- "Option prices calculated at: [" + string stopWatch.Elapsed.TotalMilliseconds + "]"::stats) 
    printfn "%f" stopWatch.Elapsed.TotalMilliseconds 

    //Write results and statistics 
    writeFile outputFile results 
    ignore(stats <- "Output file written at: [" + string stopWatch.Elapsed.TotalMilliseconds + "]"::stats) 

    ignore(stats <- "Total Ellapsed Time (minus stats file write): [" + string (stopWatch.Elapsed.TotalMilliseconds/60000.0) + "] minutes"::stats) 
    printfn "%f" stopWatch.Elapsed.TotalMilliseconds 

    writeFile statsfile (stats |> List.rev) 
    stopWatch.Stop() 
    ignore(Console.ReadLine()) 
+0

如果您需要任何幫助,您將需要發佈代碼 - 我們不是精神病患者 –

+1

嘗試在v4上使用'ngen'。看起來很奇怪,但有可能它不是'原始'。 –

+0

如果使用'fsc.exe'編譯代碼,您是否也會看到類似的差異? –

回答

2

我還沒有運行的代碼,但它看起來像你創建大量的鏈表。這是非常低效的,但近年來,名單的表述發生了變化,而新的表示方式則較慢。