【发布时间】:2016-04-18 22:50:40
【问题描述】:
This is a detailed answer 关于在 IEnumerator<T> 是可变结构的情况下 C# 编译器如何优化 foreach。
F# 编译器是否执行相同的优化?
【问题讨论】:
This is a detailed answer 关于在 IEnumerator<T> 是可变结构的情况下 C# 编译器如何优化 foreach。
F# 编译器是否执行相同的优化?
【问题讨论】:
AFAICT 似乎 F# 对待 valuetype 枚举器的方式与 C# 类似:
这里是一个简单的 C# 程序的 IL 代码的反汇编 sn-p,该程序在 IEnumerable<T> 上使用 foreach
.locals init (
[0] valuetype [mscorlib]System.Collections.Generic.List`1/Enumerator<int32>,
[1] int32 v
)
IL_0025: ldloca.s 0
IL_0027: call instance bool valuetype [mscorlib]System.Collections.Generic.List`1/Enumerator<int32>::MoveNext()
注意local 0 是一个值类型,它使用ldloca.s 来加载结构的地址。
与 F# 比较
.locals init (
[0] class [mscorlib]System.Collections.Generic.List`1<int32> ra,
[1] valuetype [mscorlib]System.Collections.Generic.List`1/Enumerator<int32>
)
IL_000e: ldloca.s 1
IL_0010: call instance bool valuetype [mscorlib]System.Collections.Generic.List`1/Enumerator<int32>::MoveNext()
此代码还使用 valuetype 声明 local 1 和 ldloca.s 以加载结构的地址。
附带说明:后来的 F# 版本实际上做了 C# 不做的优化。因为在 F# 中迭代作为不可变数据结构的 F# 列表是一种常见模式,所以使用枚举器进行迭代是无效的。所以 F# 对列表有一个特殊情况,并在这种情况下应用更有效的算法。在 C# 中迭代 F# 列表将回退到枚举器。
也可以对IList 类型实现特殊处理,但由于可能有人以“有趣”的方式实现了IList,因此实现这种优化可能是一个突破性的变化。
【讨论】: