在C#之间> 0和> = 1哪个更快更好?

时间:2010-09-07 18:32:35

标签: c# performance

在C#之间> 0和> = 1哪个更快更好?

11 个答案:

答案 0 :(得分:45)

既不;如果一个更快或更好,他们都应该编译成同样的东西。

更重要的是,大多数程序员可能会发现> 0更具可读性,可读性比这样的微观优化更重要。

答案 1 :(得分:27)

更好的是最清楚地表达你的意图的那个

如果您正在测试整数是否在[1,6]范围内,那么您应该将其写为:

 if (x >= 1 && x <= 6) { ... }

写这个可行,但不那么明显符合规范:

 if (x > 0 && x < 7) { ... }

我也假设你在这里讨论整数类型。如果您正在处理浮点数或十进制数,那么它们就不等价。


除非您对代码进行了分析并发现这是瓶颈,否则您不必担心微观优化问题。即便如此,在每种情况下检查C#编译器生成的代码以查看它们是否编译为相同的IL都是有趣的。这可以通过使用.NET Reflector来完成。

if (x >= 1)
{
    Console.WriteLine("True!");
}

结果:

L_000b: ldloc.0          // Load the value of x
L_000c: ldc.i4.1         // Load the constant 1 
L_000d: blt.s L_0019     // Branch if less than
L_000f: ldstr "True!"
L_0014: call void [mscorlib]System.Console::WriteLine(string)

鉴于:

if (x > 0)
{
    Console.WriteLine("True!");
}

产生以下IL:

L_000b: ldloc.0          // Load the value of x
L_000c: ldc.i4.0         // Load the constant 0
L_000d: ble.s L_0019     // Branch if less than or equal
L_000f: ldstr "True!"
L_0014: call void [mscorlib]System.Console::WriteLine(string)

在这两种情况下,编译器都颠倒了比较。 “大于或等于”测试编译为“小于”指令,“大于”测试编译为“小于或等于”。通常,编译器可以自由地进行这样的修改,并且运行不同版本的编译器可能会产生不同的(但等效的)字节码。

鉴于它们没有编译到同一个IL,查看哪个最快的最好方法是在循环中实际运行代码并查看每个版本执行需要多长时间。我试过这样做但是我没有看到编写代码的两种方法之间存在任何可衡量的性能差异。

答案 2 :(得分:12)

未定义。您明确要求C# - 但这取决于处理器体系结构,即CLR运行时编译器。

答案 3 :(得分:7)

两者之间的性能差异可以忽略不计(如果有的话)。我正在努力证明它可能是什么(它将取决于平台,因为任何不同可能会归结为JIT发出和执行的代码)。

请记住,性能明智,这是一种极端的微观优化很可能是没有根据的。

更好的选择是更具可读性,并在您的代码中最好地传达您的意图。

答案 4 :(得分:4)

当然,这取决于运行程序的CPU架构。在x86上,此处相关的jgejg指令采用相同数量的周期IIRC。在测试&gt; 0的特定情况下,如果你使用无符号整数,它可能(我真的不知道)使用test指令代替cmp更快,因为对于unsigned整数&gt; 0相当于!= 0.其他架构可能不同。关键在于,它是如此低级,即使在极少数情况下值得优化,也没有与硬件无关的优化方式。

编辑:忘记提及:任何有价值的编译器或虚拟机都应该能够确定测试&gt; = 1相当于测试&gt; 0并且如果它甚至在程序集中产生差异则执行这样一个简单的优化语言水平。

答案 5 :(得分:3)

我同意其他回应,通常不应考虑微观优化。然而,看到两个版本中哪一个具有较小/明显_更快的IL可能会很有趣。

所以:

using System;

namespace IL_Test
{
    class Program
    {
        static void Main(string[] args)
        {
            int i = 3;
            if (i > 0)
            {
                Console.Write("i is greater than zero");
            }
        }
    }
}

转换为:

(DEBUG)

.method private hidebysig static void Main(string[] args) cil managed
{
    .entrypoint
    .maxstack 2
    .locals init (
        [0] int32 i,
        [1] bool CS$4$0000)
    L_0000: nop 
    L_0001: ldc.i4.3 
    L_0002: stloc.0 
    L_0003: ldloc.0 
    L_0004: ldc.i4.0 
    L_0005: cgt 
    L_0007: ldc.i4.0 
    L_0008: ceq 
    L_000a: stloc.1 
    L_000b: ldloc.1 
    L_000c: brtrue.s L_001b
    L_000e: nop 
    L_000f: ldstr "i is greater than zero"
    L_0014: call void [mscorlib]System.Console::Write(string)
    L_0019: nop 
    L_001a: nop 
    L_001b: ret 
}

(RELEASE)

.method private hidebysig static void Main(string[] args) cil managed
{
    .entrypoint
    .maxstack 2
    .locals init (
        [0] int32 i)
    L_0000: ldc.i4.3 
    L_0001: stloc.0 
    L_0002: ldloc.0 
    L_0003: ldc.i4.0 
    L_0004: ble.s L_0010
    L_0006: ldstr "i is greater than zero"
    L_000b: call void [mscorlib]System.Console::Write(string)
    L_0010: ret 
}

,而

using System;

namespace IL_Test
{
    class Program
    {
        static void Main(string[] args)
        {
            int i = 3;
            if (i >= 1)
            {
                Console.Write("i is greater than zero");
            }
        }
    }
}

(DEBUG)

.method private hidebysig static void Main(string[] args) cil managed
{
    .entrypoint
    .maxstack 2
    .locals init (
        [0] int32 i,
        [1] bool CS$4$0000)
    L_0000: nop 
    L_0001: ldc.i4.3 
    L_0002: stloc.0 
    L_0003: ldloc.0 
    L_0004: ldc.i4.1 
    L_0005: clt 
    L_0007: stloc.1 
    L_0008: ldloc.1 
    L_0009: brtrue.s L_0018
    L_000b: nop 
    L_000c: ldstr "i is greater than zero"
    L_0011: call void [mscorlib]System.Console::Write(string)
    L_0016: nop 
    L_0017: nop 
    L_0018: ret 
}

(RELEASE)

.method private hidebysig static void Main(string[] args) cil managed
{
    .entrypoint
    .maxstack 2
    .locals init (
        [0] int32 i)
    L_0000: ldc.i4.3 
    L_0001: stloc.0 
    L_0002: ldloc.0 
    L_0003: ldc.i4.1 
    L_0004: blt.s L_0010
    L_0006: ldstr "i is greater than zero"
    L_000b: call void [mscorlib]System.Console::Write(string)
    L_0010: ret 
}

据我所知,i&gt; = 1比i> 0 IN DEBUG MODE

略快

在释放模式中,所有差异都在偏移0004 a BLE与BLT之间。我想这两个IL操作转换为同样CPU消耗的本地操作..

答案 6 :(得分:2)

没有区别,因为cpu在内部对两个数字进行减法并检查结果和溢出。两种指令都没有额外的步骤。

说到代码,它取决于您要记录的内容。 &gt; = 1表示1是可能的最低数字。 &GT; 0表示不允许0。专业人员会注意到一个小的语义差异。他们会选择合适的操作员来记录他们的意图。

如果你认为&gt; = n和&gt; = n + 1是相同的,你就错了:&gt; = int.MaxValue和&gt; (int.MaxValue + 1)是不同的^^

答案 7 :(得分:1)

为了回答更快的问题,我不确定,但我认为它们是等效的。为了更好地回答,我认为这取决于背景。

答案 8 :(得分:0)

除非可能在应用程序中性能至关重要的非常紧密的循环中,否则您不会发现任何差异。然后你需要分析你的代码,以决定哪个更好。

使用在您的应用程序中最有意义的那个。

答案 9 :(得分:0)

通常当我将某些内容与&gt;进行比较时0或&gt; = 1,我试图查看数组/集合是否包含任何元素。如果是这种情况,请尝试使用.Count > 0中的辅助方法Enumerable.Any(),而不是使用System.Linq,而应该更快。

否则,我不知道:)。

答案 10 :(得分:0)

如果两者之间存在差异,那么我会说这将是一种微优化,不应该影响应用程序的整体性能。

此外,当一个人真正弄清楚他是否必须使用&gt; 0或&gt; = 1,然后我会说出确定哪一个更快的成本,并不会超过(最小)性能优势。

因此,我还要说你应该使用最能表达意图的选项。