performance - Seq.map 比常规 for 循环更快?

标签 performance f#

我正在学习 F#,关于这种语言的一件事是性能。我编写了一个小型基准测试,将惯用的 F# 与用相同语言编写的命令式代码进行比较 - 令我惊讶的是,函数式版本的运行速度明显更快。

基准包括:

  • 使用 File.ReadAllLines 读入文本文件
  • 反转每行中的字符顺序
  • 使用 File.WriteAllLines 将结果写回同一个文件。

  • 这是代码:
    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
    

    无论文件的大小如何,“F# 风格”版本的完成时间大约是“C# 风格”版本的 75%。我的问题是,为什么会这样?我认为命令式版本没有明显的低效率。

    最佳答案

    Seq.map不同于 Array.map .因为序列 ( IEnumerable<T> ) 在被枚举之前不会被评估,在 F# 风格的代码中,直到 File.WriteAllLines 才真正发生计算。循环遍历由 Seq.map 生成的序列(不是数组) .

    换句话说,您的 C# 样式版本正在反转所有字符串并将反转后的字符串存储在一个数组中,然后循环遍历该数组以写出到文件中。 F# 风格的版本正在反转所有字符串并将它们或多或少地直接写入文件。这意味着 C# 风格的代码在整个文件中循环了 3 次(读取到数组、构建反向数组、将数组写入到文件中),而 F# 风格的代码只循环了整个文件两次(读取到数组、写入反转行到文件)。

    如果您使用 File.ReadLines,您将获得最佳性能而不是 File.ReadAllLines结合 Seq.map - 但是您的输出文件必须与您的输入文件不同,因为您在写入输出的同时仍然从输入中读取。

    关于performance - Seq.map 比常规 for 循环更快?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/10468422/

    相关文章:

    postgresql - 调整两列与一组整数的比较

    Javascript 模块声明 - 性能

    f# - 如何在 F# 中打印一个 bigint?

    .NET 微型上的 F#

    f# - FSharp.核心 : Could not load file or assembly

    f# - 4.5 版中的阴影

    performance - 如何在资源不足的设备上测试算法性能?

    Python MySQL SELECT WHERE 带列表

    performance - 在 IntelliJ 上运行 JProfiler for grails

    mysql - 将 MySQL 表转换为 F# 矩阵