gpt4 book ai didi

f# - 为什么 reduce 比 sum 或 sumBy 快?

转载 作者:行者123 更新时间:2023-12-03 23:23:16 24 4
gpt4 key购买 nike

我和我的同事正在比较 C# 函数在传递 lambda 进行工作时的速度与内联函数在工作时间方面的比较。我们发现您在将 lambda 投影传递给 C# 选择函数(例如)时会产生成本,并想看看 F# 是否有相同的问题,或者它是否做了不同的事情。

不管我们最初的意图如何,我们偶然发现了一些我们无法弄清楚的东西。在下面的例子中,我们总结了一个列表 3 种不同的方式

  • 减少
  • 总和
  • SumBy

  • module fs

    open NUnit.Framework
    open FsUnit
    open System
    open System.Diagnostics;

    [<Test>]
    let sumTest() =
    let nums = [0..1000]

    let repeat = 100000

    let stopWatch = new Stopwatch()

    stopWatch.Start()

    let sumsReduce =
    [
    for i in [0..repeat] do
    yield List.reduce (+) nums
    ]

    Console.WriteLine("reduce = {0} - Time = {1}", List.head sumsReduce, stopWatch.Elapsed.TotalSeconds);
    stopWatch.Restart()

    let sumsSum =
    [
    for i in [0..repeat] do
    yield List.sum nums
    ]

    Console.WriteLine("sum = {0} - Time = {1}", List.head sumsSum, stopWatch.Elapsed.TotalSeconds);
    stopWatch.Restart()


    let sumsSumBy =
    [
    for i in [0..repeat] do
    yield List.sumBy id nums
    ]

    Console.WriteLine("sumBy = {0} - Time = {1}", List.head sumsSumBy, stopWatch.Elapsed.TotalSeconds);
    stopWatch.Restart()

    输出如下:
    reduce = 500500 - Time = 0.2725156
    sum = 500500 - Time = 1.1183165
    sumBy = 500500 - Time = 1.1126781

    所以很明显reduce是这里的大赢家。在反编译中,我可以看到 reduce 被归结为
    [Serializable]
    internal class sumsReduce\u004021\u002D1 : OptimizedClosures.FSharpFunc<int, int, int>
    {
    internal sumsReduce\u004021\u002D1()
    {
    base.\u002Ector();
    }

    public override int Invoke(int x, int y)
    {
    return x + y;
    }
    }

    但我很难弄清楚 sum 和 sumBy 在做什么。时间差异来自哪里?

    当前的答案表明 reduce 快 5 倍,因为最初我给 reduce 一个未经检查的运算符。但是,更新测试以使用检查运算符(来自 Checked 模块),我仍然得到相同的结果
    let sumsReduce = 
    [
    for i in [0..repeat] do
    yield List.reduce (Checked.(+)) nums
    ]

    注意时间差异仍然存在
    reduce = 500500 - Time = 0.274697
    sum = 500500 - Time = 1.1126796
    sumBy = 500500 - Time = 1.1370642

    最佳答案

    Sum 和 SumBy 使用枚举器:

        while e.MoveNext() do
    acc <- Checked.(+) acc e.Current
    acc

    而 reduce 使用带有优化闭包的递归循环:(reduce 使用 fold under the cover - fold f head tail )
        let fold<'T,'State> f (s:'State) (list: 'T list) = 
    match list with
    | [] -> s
    | _ ->
    let f = OptimizedClosures.FSharpFunc<_,_,_>.Adapt(f)
    let rec loop s xs =
    match xs with
    | [] -> s
    | h::t -> loop (f.Invoke(s,h)) t
    loop s list

    使用优化的闭包通常可以提高性能。

    关于f# - 为什么 reduce 比 sum 或 sumBy 快?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/18367192/

    24 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com