C#编译器优化

C#编译器优化,c#,optimization,compiler-optimization,C#,Optimization,Compiler Optimization,编译器为什么要优化我的代码 我有两个功能: public void x1() { x++; x++; } public void x2() { x += 2; } public void x3() { x = x + 2; } public void y3() { x = x * x + x * x; } 这就是我在发布模式下编译后看到的ILSpy: // test1.Something public void x1() { this.x++; this.x

编译器为什么要优化我的代码

我有两个功能:

public void x1() {
  x++;
  x++;
}
public void x2() {
  x += 2;
}
public void x3() {
  x = x + 2;
}
public void y3() {
  x = x * x + x * x;
}
这就是我在发布模式下编译后看到的ILSpy:

// test1.Something
public void x1()
{
    this.x++;
    this.x++;
}

// test1.Something
public void x2()
{
    this.x += 2;
}
// test1.Something
public void x3()
{ 
    this.x += 2;
}
// test1.Something
public void y3()
{
    this.x = this.x * this.x + this.x * this.x;
}
x2和x3可能还可以。但是为什么x1没有优化到相同的结果呢?没有理由保持2步增量? 为什么y3不是
x=2*(x*x)
?这不应该比
x*x+x*x
快吗

这就引出了问题?如果不是这样简单的事情,C#编译器会做什么样的优化

当我读到你经常听到的关于编写代码的文章时,把它写成可读的,编译器就会完成剩下的工作。但在这种情况下,编译器几乎什么也不做


再添加一个示例:

public void x1() {
  int a = 1;
  int b = 1;
  int c = 1;
  x = a + b + c;
}
以及使用ILSpy:

// test1.Something
public void x1()
{
    int a = 1;
    int b = 1;
    int c = 1;
    this.x = a + b + c;
}

为什么不是这个.x=3?

x1
x2
不一样:

如果
x
是一个公共字段,并且是在多线程环境中访问的,那么第二个线程完全有可能在两次调用之间发生
x
变异,这在
x2
中的代码是不可能的

对于
y2
,如果
+
和/或
*
x
类型重载,则
x*x+x*x
可能不同于
2*x*x

编译器将优化以下内容(不是详尽的列表):

  • 删除未使用的局部变量(释放寄存器)
  • 删除不影响逻辑流或输出的代码
  • 对简单方法的内联调用
编译器优化不应该改变程序的行为(尽管它确实发生了)。因此,重新排序/组合数学运算超出了优化范围

把它写得可读,编译器将完成其余的工作


嗯,编译器可能会做一些优化,但在设计时仍有很多工作可以做以提高性能。是的,可读代码确实很有价值,但编译器的工作是生成与源代码相对应的工作IL,而不是将源代码更改得更快。

如果不假设变量
x
不会与正在运行的方法同时访问,编译器就无法执行此优化。否则,可能会以可检测的方式改变方法的行为

考虑这样一种情况,即从两个线程同时访问
this
引用的对象。踏板
A
反复将
x
设置为零;线程
B
反复调用
x1()

如果编译器将
x1
优化为与
x2
等效,则在您的实验之后,
x
的两个可观察状态将是
0
2

  • 如果
    A
    B
    之前完成,您将得到
    2
  • 如果
    B
    A
    之前完成,则得到
    0

如果<代码> A/COD>在中间预置<代码> B<代码>,则仍将得到<代码> 2 < /C> > < /P> 但是,原始版本的

x1
允许三种结果:
x
最终可能是
0
1
2

  • 如果
    A
    B
    之前完成,您将得到
    2
  • 如果
    B
    A
    之前完成,则得到
    0
  • 如果
    B
    在第一次增量后被抢占,然后
    A
    完成,然后
    B
    运行到完成,则得到
    1

是什么让你相信
x=2*(x*x)
x=x*x+x*x
更优化?可读性或术语的缩减并不意味着公式运算更加优化,有时扩展它意味着其更加优化。1。大多数优化在运行时由JIT编译器执行,而不是由C#编译器执行。2.对于多线程,您建议的
x1
优化在功能上是不等价的(例如,如果字段是可变的,则编译器绝对不允许执行建议的优化)。这里有一篇关于C#编译器确实执行的优化的文章:代码越少并不意味着性能越好,x++是一种特殊情况,因为它涉及缓存要返回的值,然后对其进行递增。2次乘法是否不比2次乘法和一次加法快?我添加了一个与多线程无关的新示例?--顺便问一下,如果编译器可以对指令进行重新排序以优化性能,并且您需要采取诸如MemoryFences之类的特殊操作来防止这种情况发生,那么为什么组合x++和x++会有所不同呢?如果没有锁或MemoryBarrier,我希望编译器不关心多线程。我认为您对编译器的期望太高了。它的工作是将您的源代码转换为可工作的IL,而不是找到每一个可以让您的代码更快的地方并为您重新编码。如果你觉得这是下一个C#编译器的一个有价值的特性,那么就把它发布出来,看看会发生什么。另外,为什么要到此为止?为什么不将
列表
更改为
数组
?为什么不将您的
if
语句系列更改为
开关
?或者,如果条件永远不可能为真,则删除一个
if
块?许多人都会抱怨编译器的速度不够快。我们问题的基本答案是:任何功能都必须经过设计、编码、测试、记录和支持,所有这些都需要花费时间和金钱,而其他许多功能都在竞争。如果这样一个特性的好处不超过成本(或者如果其他特性提供更多好处),那么它就不会被生产出来。我想这种优化的好处是微乎其微的。@bebo编译器生成IL,它甚至不尝试优化。JIT的工作是在此基础上执行依赖于平台的优化。信息技术