将C#编译器优化此代码?

问题描述 投票:0回答:1
GetOtherThing

方法的内容?说看起来像这样(与我的真实代码有些相似):

public OtherThing GetOtherThing() {
    if (this.Category == null) return null;
    return this.Category.OtherThings.FirstOrDefault(t => t.Text == this.Text);
}

将除了对这些物体来自任何存储的任何商店的处理非常差的异步更改,如果连续两次运行,则一定要返回同一件事。但是,如果看起来像这样(为了论证而毫无意义的例子):

public OtherThing GetOtherThing() {
    return new OtherThing {
        Id = new Random().Next(100)
    };
}

连续两次交易将导致创建两个不同的对象,并具有不同的ID。在这些情况下,编译器会做什么?它看起来像我在第一个列表中所显示的事情一样效率低下吗?

我自己做一些工作

我运行了与第一个代码列表非常相似的东西,并在
GetOtherThing

实例方法中放了一个断点。断点一次击中。因此,看起来结果确实被缓存。在第二种情况下,该方法可能每次都会返回不同的东西?编译器会错误地优化吗?我发现的结果是否有警告?

eDit


结论无效。请参阅 @usr的答案下的评论。
    

有两个编译器要在此处考虑:将C#变成IL的C#编译器,以及将IL变成机器代码的IL编译器 - 称为抖动,因为它会及时发生。 Microsoft C#编译器当然没有这种优化。方法调用是作为方法调用生成的,故事的结尾。

允许抖动执行您描述的优化。 例如,假设您有: y = M() != 0 ? M() : N()

c# .net optimization
1个回答
12
投票

抖动是permittit的

将此程序变成:

y = 1 != 0 ? 1 : N()

或为此 y = 1;

抖动是否这样做是实施细节;您必须询问抖动中的专家,如果您在乎,它是否确实确实执行了此优化。

相似,如果您有

static int m; static int M() { return m; }

然后抖动可以将其优化为

y = m != 0 ? m : N() 或甚至:

int q = m;
y = q != 0 ? q : N();

由于抖动可以连续将两个字段读取,而没有中间写入单个字段读取,前提是该字段不挥发。 同样,是否这样做是实施细节;询问抖动开发人员。

,但是,在您的后一个示例中,抖动无法散发第二个呼叫,因为它具有副作用。
  我运行了与第一个代码列表非常相似的东西,并在Getotherthing实例方法中放了一个断点。断点一次击中。

极不可能。当您调试时,几乎所有优化都会关闭,因此更容易调试。 正如herlock福尔摩斯从未说过的那样,当您消除不可能的情况时,最可能的解释是原始海报被错误了。

在您无法分辨差异的情况下,编译器才能应用优化。在您的“随机”示例中,您可以清楚地分辨出区别。它不能以这种方式“优化”。它将违反C#规格。实际上,该规格并没有经常谈论优化。它只是说您应该观察到该计划的内容。在这种情况下,它指定应绘制两个随机数。

在第一个示例中,可能可以应用此优化。它永远不会在实践中发生。这是一些使它很难的事情:

查询操作的数据可以通过您的虚拟函数调用更改,或者您的lambda(
t => t.Text == this.Text

)可以更改列表。非常阴险

可以通过另一个线程更改。我不确定.NET内存模型对此有何评价。
可以通过反射更改。
必须证明,计算将始终返回相同的值。您将如何证明这一点?您将需要分析所有可能运行的代码。包括虚拟呼叫和数据依赖性控制流。

所有这些都必须跨非内部方法和跨组件进行工作。

C#编译器无法执行此操作,因为它无法查看Mscorlib。补丁发布可能随时更改Mscorlib。

jit是一个差的JIT(alas),并且对汇编速度(a)进行了优化。它不这样做。如果您怀疑当前的JIT是否会进行一些高级优化,那是一个安全的选择。

最新问题
© www.soinside.com 2019 - 2025. All rights reserved.