And*_*rew 7 .net c# compiler-construction optimization
我经常遇到这种情况.乍一看,我认为,"这是糟糕的编码; 我正在执行一个方法两次并且必然会得到相同的结果."但是在想到这一点时,我不得不怀疑编译器是否像我一样聪明并且可以得出相同的结论.
var newList = oldList.Select(x => new Thing {
FullName = String.Format("{0} {1}", x.FirstName, x.LastName),
OtherThingId = x.GetOtherThing() != null : x.GetOtherThing().Id : 0 // Might call x.GetOtherThing() twice?
});
Run Code Online (Sandbox Code Playgroud)
编译器的行为是否依赖于GetOtherThing方法的内容?说它看起来像这样(有点类似于我现在的真实代码):
public OtherThing GetOtherThing() {
if (this.Category == null) return null;
return this.Category.OtherThings.FirstOrDefault(t => t.Text == this.Text);
}
Run Code Online (Sandbox Code Playgroud)
这将禁止对这些对象来自的任何商店进行非常糟糕的异步更改,如果连续运行两次,肯定会返回相同的内容.但如果它看起来像这样(为了论证而荒谬的例子):
public OtherThing GetOtherThing() {
return new OtherThing {
Id = new Random().Next(100)
};
}
Run Code Online (Sandbox Code Playgroud)
连续两次运行会导致创建两个不同的对象,并且很可能具有不同的ID.编译器在这些情况下会做什么?它是否像我在第一个清单中所展示的那样低效?
我运行了与第一个代码清单非常相似的东西,并在GetOtherThing实例方法中添加了一个断点.断点被击中一次.所以,看起来结果确实是缓存的.在第二种情况下会发生什么,该方法可能每次返回不同的东西?编译器会不正确地优化?我发现结果有什么警告吗?
编辑
那个结论无效.请参阅@ usr的答案下的评论.
Eri*_*ert 12
这里有两个编译器需要考虑:将C#转换为IL的C#编译器,以及将IL转换为机器代码的IL编译器 - 称为抖动,因为它恰好发生在时间上.
Microsoft C#编译器肯定没有这样的优化.方法调用生成为方法调用,故事结束.
允许抖动执行您描述的优化,前提是无法检测到这种情况.例如,假设你有:
y = M() != 0 ? M() : N()
Run Code Online (Sandbox Code Playgroud)
和
static int M() { return 1; }
Run Code Online (Sandbox Code Playgroud)
允许抖动将此程序转换为:
y = 1 != 0 ? 1 : N()
Run Code Online (Sandbox Code Playgroud)
或者就此而言
y = 1;
Run Code Online (Sandbox Code Playgroud)
抖动是否这样做是一个实现细节; 如果你关心的话,你将不得不向专家询问抖动是否确实会执行此优化.
同样,如果你有
static int m;
static int M() { return m; }
Run Code Online (Sandbox Code Playgroud)
那么抖动可以将其优化成
y = m != 0 ? m : N()
Run Code Online (Sandbox Code Playgroud)
甚至进入:
int q = m;
y = q != 0 ? q : N();
Run Code Online (Sandbox Code Playgroud)
因为只要该字段不是易失性的,就允许抖动连续转换两个字段读取而不插入单个字段读取.无论它是否这样做都是一个实现细节; 问一个抖动的开发人员.
但是,在后一个例子中,抖动不能忽略第二次调用,因为它有副作用.
我运行了与第一个代码清单非常相似的东西,并在GetOtherThing实例方法中放置了一个断点.断点被击中一次.
这是非常不可能的.调试时几乎所有优化都会关闭,这样就可以更容易地进行调试.正如福尔摩斯从未说过的那样,当你消除不可能的事情时,最可能的解释是原来的海报是错误的.
如果您无法区分,编译器只能应用优化.在您的"随机"示例中,您可以清楚地区分出来.它不能以这种方式"优化".它会违反C#规范.事实上,该规范并未谈及优化问题.它只是说你应该观察程序做什么.在这种情况下,它指定应绘制两个随机数.
在第一个示例中,可以应用此优化.它在实践中永远不会发生.以下是一些令人困难的事情:
t => t.Text == this.Text)可以更改列表.非常阴险.所有这些都必须适用于非内联方法和跨程序集.
C#编译器无法执行此操作,因为它无法查看mscorlib.修补程序版本可能随时更改mscorlib.
JIT是一个糟糕的JIT(唉),它针对编译速度进行了优化(唉).它没有这样做.如果您怀疑当前的JIT是否会进行一些高级优化,那么可以肯定它不会.
| 归档时间: |
|
| 查看次数: |
918 次 |
| 最近记录: |