Огромная разница в производительности при запуске одного и того же кода на fsi 4.0.30319.1 и 2.0.0.0 - PullRequest
0 голосов
/ 04 октября 2011

Я использую один и тот же код F # с двумя версиями fsi.exe, которые я могу найти при установке FSharp-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, заключается в том, чтобы иметь возможность использовать 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())

1 Ответ

2 голосов
/ 06 октября 2011

Я не запускал ваш код, но, похоже, вы создаете много связанных списков. Это очень неэффективно, но представление списков было изменено в последние годы, и новое представление медленнее.

...