我正在学习F#,关于这种语言我最关心的一件事就是表现.我写了一个小基准,我将惯用的F#与用同一种语言编写的命令式代码进行比较 - 令我惊讶的是,功能版本的出现速度明显更快.
基准包括:
这是代码:
open System
open System.IO
open System.Diagnostics
let reverseString(str:string) =
new string(Array.rev(str.ToCharArray()))
let CSharpStyle() =
let lines = File.ReadAllLines("text.txt")
for i in 0 .. lines.Length - 1 do
lines.[i] <- reverseString(lines.[i])
File.WriteAllLines("text.txt", lines)
let FSharpStyle() =
File.ReadAllLines("text.txt")
|> Seq.map reverseString
|> (fun lines -> File.WriteAllLines("text.txt", lines))
let benchmark func message =
// initial call for warm-up
func()
let sw = Stopwatch.StartNew()
for i in 0 .. 19 do
func()
printfn message sw.ElapsedMilliseconds
[<EntryPoint>]
let main args =
benchmark CSharpStyle "C# time: %d ms"
benchmark FSharpStyle "F# time: %d ms"
0
Run Code Online (Sandbox Code Playgroud)
无论文件大小如何,"F#风格"版本在"C#风格"版本的大约75%的时间内完成.我的问题是,为什么?我发现命令式版本没有明显的低效率.
Joe*_*ler 10
Seq.map
不同于Array.map
.因为IEnumerable<T>
在枚举之前不会对values()进行求值,所以在F#样式代码中,在File.WriteAllLines
通过生成的序列(不是数组)循环之前,实际上不会发生任何计算Seq.map
.
换句话说,你的C#风格版本正在反转所有字符串并将反转的字符串存储在一个数组中,然后循环遍历数组以写出文件.F#风格版本正在反转所有字符串,并将它们或多或少地直接写入文件.这意味着C#风格代码通过整个文件三次循环(读取到阵列,构建反向阵列,写入阵列到文件),而F#风格的代码通过整个文件循环只有两次(读取到阵列中,写反向行到文件).
如果您使用File.ReadLines
而不是File.ReadAllLines
组合使用,那么您将获得最佳性能Seq.map
- 但您的输出文件必须与输入文件不同,因为您仍然在从输入读取时写入输出.
归档时间: |
|
查看次数: |
415 次 |
最近记录: |