c#中的++i和i += 1在性能上有什么区别吗?
本文关键字:性能 什么 区别 ++i 中的 | 更新日期: 2023-09-27 18:04:18
i += a应等价于i = i + a。在a == 1的情况下,这应该不如++i高效,因为它涉及到更多的内存访问;或者编译器会使它与++i完全相同吗?
很容易回答:c#编译器将c#源代码转换为IL操作码。没有专用的IL操作码来执行相当于++操作符的操作。如果使用ildasm.exe工具查看生成的IL,就很容易看出这一点。这个示例c#代码片段:
int ix = 0;
ix++;
ix = ix + 1;
生成:
IL_0000: ldc.i4.0 // load 0
IL_0001: stloc.0 // ix = 0
IL_0002: ldloc.0 // load ix
IL_0003: ldc.i4.1 // load 1
IL_0004: add // ix + 1
IL_0005: stloc.0 // ix = ix + 1
IL_0006: ldloc.0 // load ix
IL_0007: ldc.i4.1 // load 1
IL_0008: add // ix + 1
IL_0009: stloc.0 // ix = ix + 1
生成与完全相同的代码。抖动只能生成同样快的机器码。
前/后递增运算符是c#中的语法糖,在它使你的代码更清晰的地方使用它。或者更相关的是:避免在它使不那么清晰的地方使用它。它们确实有一个诀窍,可以让你创建有很多副作用的表达式。
编译器应该以任何方式优化代码,所以我相信I = I + 1与++ I相同。
我不认为会有什么不同,但是你可以把它付诸行动,像:
class Program
{
static void Main(string[] args)
{
//Add values
List<objClass> lst1 = new List<objClass>();
for (int i = 0; i < 9000000; i++)
{
lst1.Add(new objClass("1", ""));
}
//For loop ++i
DateTime startTime = DateTime.Now;
for (int i = 0; i < 9000000; ++i)
{
lst1[i]._s1 = lst1[i]._s2;
}
Console.WriteLine((DateTime.Now - startTime).ToString());
//For loop i+=1
startTime = DateTime.Now;
for (int i = 0; i < 9000000; i+=1)
{
lst1[i]._s1 = lst1[i]._s2;
}
Console.WriteLine((DateTime.Now - startTime).ToString());
}
public class objClass
{
public string _s1 { get; set; }
public string _s2 { get; set; }
public objClass(string _s1, string _s2)
{
this._s1 = _s1;
this._s2 = _s2;
}
}
}
看情况。理论上,给定一个足够幼稚的编译器,++x
可能比x += 1
更有效。
但是,我不知道有这么幼稚的编译器。
- 如果操作数的值在编译时已知,则编译器可以优化该操作。
- 如果在运行时可以确定该值为常数,则JIT编译器也可以优化操作。
此外,现代cpu是高度复杂的野兽,可以并行执行许多操作,而且通常,像这样的"简单"操作可以通过与更大、更复杂的操作并行运行而完全隐藏起来。
一个很好的经验法则,在优化时,只是在一般情况下,尽可能清楚地表达你的意图。这使其他程序员更容易阅读您的代码,但也使编译器更容易这样做。 如果你想增加一个值,使用自增运算符( 如果要添加变量或未知值,请使用 如果你清楚你的意图,那么编译器会得到更多关于你的代码的信息,并可以相应地优化。 如果你写++
),因为它准确地描述了你想做的事情。+=
操作符,因为就是用于的。x += 1
,你实际上是在试图绊倒编译器。你说的是"使用通用加法运算符向x
添加1"。然后编译器必须弄清楚"好吧,你说要使用通用的加法,但我认为这是不必要的,所以我要用增量来代替"。你可以这么说。现在,相反,您必须依赖编译器的聪明。
除非将a定义为const int == 1,否则编译器如何在编译时知道a == 1?
所以答案一定是否定的,编译器不能把它编译成++i。