Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/asp.net-mvc/14.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Optimization “F”;for loop";优化_Optimization_F#_For Loop - Fatal编程技术网

Optimization “F”;for loop";优化

Optimization “F”;for loop";优化,optimization,f#,for-loop,Optimization,F#,For Loop,代码示例: 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 第二个是近100行,大量的分配/解除分配,调用虚拟函数,大量的try/Dispose: IL_0000: nop IL_0001: ldc.i4.0

代码示例:

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
第二个是近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
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:调用类[mscorlib]System.Collections.Generic.IEnumerable`1[FSharp.Core]Microsoft.FSharp.Core.Operators/OperatorIntrinsics::RangeInt32(int32,int32,int32)
IL_000d:调用类[mscorlib]System.Collections.Generic.IEnumerable`1[FSharp.Core]Microsoft.FSharp.Core.Operators::CreateSequence(类[mscorlib]System.Collections.Generic.IEnumerable`1)
IL_0012:调用类[FSharp.Core]Microsoft.FSharp.Collections.FSharpList`1[FSharp.Core]Microsoft.FSharp.Collections.SeqModule::ToList(类[mscorlib]System.Collections.Generic.IEnumerable`1)
IL_0017:stloc.0
IL_0018:ldloc.0
IL_0019:unbox.any class[mscorlib]System.Collections.Generic.IEnumerable`1
IL001E:callvirt实例类[mscorlib]System.Collections.Generic.IEnumerator`1类[mscorlib]System.Collections.Generic.IEnumerable`1::GetEnumerator()
IL_0023:stloc.1
尝试
{
//环路启动(磁头:IL_0024)
IL_0024:ldloc.1
IL_0025:callvirt实例bool[mscorlib]System.Collections.IEnumerator::MoveNext()
ILU 002a:brfalse.s ILU 003e
IL_002c:ldloc.1
IL_002d:callvirt实例!0类[mscorlib]System.Collections.Generic.IEnumerator`1::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:没有
IL_003c:br.s IL_0024
//端环
IL_003e:ldnull
IL_003f:stloc.2
IL_0040:离开。s IL_005b
}//结束,再试一次
最后
{
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实例无效[mscorlib]System.IDisposable::Dispose()
IL_0055:ldnull
IL_0056:流行音乐
IL_0057:endfinally
IL_0058:ldnull
IL_0059:流行音乐
IL_005a:最后
}//结束处理程序
IL_005b:ldloc.2
IL_005c:流行音乐
IL_005d:ret

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

在第二个示例中,如果使用范围表达式,它将转换为正常的
for
循环:

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

您已经明确创建了一个新列表。

您看到的是使用基于索引的枚举和基于
IEnumerable
的枚举之间的标准区别(或者用C#terms
for
vs
foreach

在第二个示例中,表达式
[0..arr.Length-1]
正在创建一个集合,而F#正在使用
IEnumerable
枚举值。此枚举样式的一部分涉及使用
IEnumerator
,它实现了
IDisposable
。生成您看到的
try/finally
块,以确保在枚举结束时调用
IDisposable::Dispose
方法,即使遇到异常也是如此

F#能否将第二个示例优化为第一个,并避免所有额外的开销?他们有可能进行这种优化。从本质上看,范围表达式不是一个简单的数字范围,因此为代码生成等效的


应该优化第二个例子。我的投票结果是否定的。像这样的功能从外观上看往往微不足道,但实际上实现它们,更重要的是维护它们,可能会相当昂贵。精明的用户总是可以将他们的代码转换回标准的
版本,并避免
IEnumerable
开销(如果探查器发现这是一个问题)。不实施优化会让F#团队腾出时间来实施其他很棒的功能

对于0..arr.Length-1 do表达式中的I,我不知道这个
。非常感谢。我还要补充一点,使用列表而不是迭代器被认为更“安全”,因为迭代器是可变的,而F#中的列表由不可变的值组成,所以没有副作用。
let foo2 (arr : int[]) = 
    for i in 0..arr.Length-1 do
        arr.[i] <- i
let foo2 (arr : int[]) = 
    let xs = [0..arr.Length-1] (* A new list is created *)
    for i in xs do
        arr.[i] <- i