gpt4 book ai didi

optimization - F# "for loop"优化

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

代码示例:

let foo1 (arr : int[]) = 
for i = 0 to arr.Length-1 do
arr.[i] <- i

let foo2 (arr : int[]) =
for i in [0..arr.Length-1] do
arr.[i] <- i

我认为这些功能应该彼此等效(在性能方面)。但是如果我们查看 IL 列表,我们会看到:

第一个函数,15 行,无动态分配,无 try运营商,没有虚拟调用:
IL_0000: nop
IL_0001: ldc.i4.0
IL_0002: stloc.0
IL_0003: br.s IL_0011
// loop start (head: IL_0011)
IL_0005: ldarg.0
IL_0006: ldloc.0
IL_0007: ldloc.0
IL_0008: stelem.any [mscorlib]System.Int32
IL_000d: ldloc.0
IL_000e: ldc.i4.1
IL_000f: add
IL_0010: stloc.0

IL_0011: ldloc.0
IL_0012: ldarg.0
IL_0013: ldlen
IL_0014: conv.i4
IL_0015: blt.s IL_0005
// end loop

IL_0017: ret

第二个 - 近 100 行,大量的分配/释放,虚函数的调用,大量的 try/ Dispose :
IL_0000: nop
IL_0001: ldc.i4.0
IL_0002: ldc.i4.1
IL_0003: ldarg.0
IL_0004: ldlen
IL_0005: conv.i4
IL_0006: ldc.i4.1
IL_0007: sub
IL_0008: call class [mscorlib]System.Collections.Generic.IEnumerable`1<int32> [FSharp.Core]Microsoft.FSharp.Core.Operators/OperatorIntrinsics::RangeInt32(int32, int32, int32)
IL_000d: call class [mscorlib]System.Collections.Generic.IEnumerable`1<!!0> [FSharp.Core]Microsoft.FSharp.Core.Operators::CreateSequence<int32>(class [mscorlib]System.Collections.Generic.IEnumerable`1<!!0>)
IL_0012: call class [FSharp.Core]Microsoft.FSharp.Collections.FSharpList`1<!!0> [FSharp.Core]Microsoft.FSharp.Collections.SeqModule::ToList<int32>(class [mscorlib]System.Collections.Generic.IEnumerable`1<!!0>)
IL_0017: stloc.0
IL_0018: ldloc.0
IL_0019: unbox.any class [mscorlib]System.Collections.Generic.IEnumerable`1<int32>
IL_001e: callvirt instance class [mscorlib]System.Collections.Generic.IEnumerator`1<!0> class [mscorlib]System.Collections.Generic.IEnumerable`1<int32>::GetEnumerator()
IL_0023: stloc.1
.try
{
// loop start (head: IL_0024)
IL_0024: ldloc.1
IL_0025: callvirt instance bool [mscorlib]System.Collections.IEnumerator::MoveNext()
IL_002a: brfalse.s IL_003e

IL_002c: ldloc.1
IL_002d: callvirt instance !0 class [mscorlib]System.Collections.Generic.IEnumerator`1<int32>::get_Current()
IL_0032: stloc.3
IL_0033: ldarg.0
IL_0034: ldloc.3
IL_0035: ldloc.3
IL_0036: stelem.any [mscorlib]System.Int32
IL_003b: nop
IL_003c: br.s IL_0024
// end loop

IL_003e: ldnull
IL_003f: stloc.2
IL_0040: leave.s IL_005b
} // end .try
finally
{
IL_0042: ldloc.1
IL_0043: isinst [mscorlib]System.IDisposable
IL_0048: stloc.s 4
IL_004a: ldloc.s 4
IL_004c: brfalse.s IL_0058

IL_004e: ldloc.s 4
IL_0050: callvirt instance void [mscorlib]System.IDisposable::Dispose()
IL_0055: ldnull
IL_0056: pop
IL_0057: endfinally

IL_0058: ldnull
IL_0059: pop
IL_005a: endfinally
} // end handler

IL_005b: ldloc.2
IL_005c: pop
IL_005d: ret

我的问题是为什么 F# 编译器对 foo2 使用如此复杂的代码?为什么它使用 IEnumerable实现如此琐碎的循环?

最佳答案

在第二个示例中,如果您使用范围表达式,它将被转换为普通 for环形:

let foo2 (arr : int[]) = 
for i in 0..arr.Length-1 do
arr.[i] <- i

并等效于 foo1 .

我报价 Section 6.3.12 Range Expressions in F# language specs :

A sequence iteration expression of the form for var in expr1 .. expr2 do expr3 done is sometimes elaborated as a simple for loop-expression (§6.5.7).



但是,您的第二个示例更像是:
let foo2 (arr : int[]) = 
let xs = [0..arr.Length-1] (* A new list is created *)
for i in xs do
arr.[i] <- i

您在其中明确创建了一个新列表。

关于optimization - F# "for loop"优化,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/10452011/

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