Vam*_*msi 65 c# performance if-statement
这些代码块中哪一个表现更好,哪一个更易读?我猜这个增益可以忽略不计,特别是在第二个区块.我只是好奇.
块#1
string height;
string width;
if (myFlag == 1)
{
height = "60%";
width = "60%";
}
else
{
height = "80%";
width = "80%";
}
Run Code Online (Sandbox Code Playgroud)
块#2
string height = "80%";
string width = "80%";
if (myFlag == 1)
{
height = "60%";
width = "60%";
}
Run Code Online (Sandbox Code Playgroud)
更新
我测试上述代码时的结果是两个块执行相同的操作
块#1
myFlag = 1: 3 Milliseconds
myFlag = 0: 3 Milliseconds
Run Code Online (Sandbox Code Playgroud)
块#2
myFlag = 1: 3 Milliseconds
myFlag = 0: 3 Milliseconds
Run Code Online (Sandbox Code Playgroud)
但是我在这里注意到的一件重要的事情(感谢Matthew Steeples在这里回答)是因为我测试的代码块没有使用变量高度和宽度,除了if-else中的赋值和if代码块1的块和编译器分别通过完全删除问题中的if和if-else块来优化IL代码,从而在此处显示我们测试的无效结果.
我已经更新了两个代码块,将高度和宽度的值写入文件,从而再次使用它们并强制编译器运行我们的测试块(我希望),但是你可以从代码中观察到实际的文件写入部分不影响我们的测试结果
这是更新的结果,C#和IL代码
结果
块#1
myFlag = 1: 1688 Milliseconds
myFlag = 0: 1664 Milliseconds
Run Code Online (Sandbox Code Playgroud)
块#2
myFlag = 1: 1700 Milliseconds
myFlag = 0: 1677 Milliseconds
Run Code Online (Sandbox Code Playgroud)
C#.net代码
块#1
public long WithIfAndElse(int myFlag)
{
Stopwatch myTimer = new Stopwatch();
string someString = "";
myTimer.Start();
for (int i = 0; i < 1000000; i++)
{
string height;
string width;
if (myFlag == 1)
{
height = "60%";
width = "60%";
}
else
{
height = "80%";
width = "80%";
}
someString = "Height: " + height + Environment.NewLine + "Width: " + width;
}
myTimer.Stop();
File.WriteAllText("testifelse.txt", someString);
return myTimer.ElapsedMilliseconds;
}
Run Code Online (Sandbox Code Playgroud)
块#2
public long WithOnlyIf(int myFlag)
{
Stopwatch myTimer = new Stopwatch();
string someString = "";
myTimer.Start();
for (int i = 0; i < 1000000; i++)
{
string height = "80%";
string width = "80%";
if (myFlag == 1)
{
height = "60%";
width = "60%";
}
someString = "Height: " + height + Environment.NewLine + "Width: " + width;
}
myTimer.Stop();
File.WriteAllText("testif.txt", someString);
return myTimer.ElapsedMilliseconds;
}
Run Code Online (Sandbox Code Playgroud)
IL代码由ildasm.exe生成
块#1
.method public hidebysig instance int64 WithIfAndElse(int32 myFlag) cil managed
{
// Code size 144 (0x90)
.maxstack 3
.locals init ([0] class [System]System.Diagnostics.Stopwatch myTimer,
[1] string someString,
[2] int32 i,
[3] string height,
[4] string width,
[5] string[] CS$0$0000)
IL_0000: newobj instance void [System]System.Diagnostics.Stopwatch::.ctor()
IL_0005: stloc.0
IL_0006: ldstr ""
IL_000b: stloc.1
IL_000c: ldloc.0
IL_000d: callvirt instance void [System]System.Diagnostics.Stopwatch::Start()
IL_0012: ldc.i4.0
IL_0013: stloc.2
IL_0014: br.s IL_0070
IL_0016: ldarg.1
IL_0017: ldc.i4.1
IL_0018: bne.un.s IL_0029
IL_001a: ldstr "60%"
IL_001f: stloc.3
IL_0020: ldstr "60%"
IL_0025: stloc.s width
IL_0027: br.s IL_0036
IL_0029: ldstr "80%"
IL_002e: stloc.3
IL_002f: ldstr "80%"
IL_0034: stloc.s width
IL_0036: ldc.i4.5
IL_0037: newarr [mscorlib]System.String
IL_003c: stloc.s CS$0$0000
IL_003e: ldloc.s CS$0$0000
IL_0040: ldc.i4.0
IL_0041: ldstr "Height: "
IL_0046: stelem.ref
IL_0047: ldloc.s CS$0$0000
IL_0049: ldc.i4.1
IL_004a: ldloc.3
IL_004b: stelem.ref
IL_004c: ldloc.s CS$0$0000
IL_004e: ldc.i4.2
IL_004f: call string [mscorlib]System.Environment::get_NewLine()
IL_0054: stelem.ref
IL_0055: ldloc.s CS$0$0000
IL_0057: ldc.i4.3
IL_0058: ldstr "Width: "
IL_005d: stelem.ref
IL_005e: ldloc.s CS$0$0000
IL_0060: ldc.i4.4
IL_0061: ldloc.s width
IL_0063: stelem.ref
IL_0064: ldloc.s CS$0$0000
IL_0066: call string [mscorlib]System.String::Concat(string[])
IL_006b: stloc.1
IL_006c: ldloc.2
IL_006d: ldc.i4.1
IL_006e: add
IL_006f: stloc.2
IL_0070: ldloc.2
IL_0071: ldc.i4 0xf4240
IL_0076: blt.s IL_0016
IL_0078: ldloc.0
IL_0079: callvirt instance void [System]System.Diagnostics.Stopwatch::Stop()
IL_007e: ldstr "testifelse.txt"
IL_0083: ldloc.1
IL_0084: call void [mscorlib]System.IO.File::WriteAllText(string,
string)
IL_0089: ldloc.0
IL_008a: callvirt instance int64 [System]System.Diagnostics.Stopwatch::get_ElapsedMilliseconds()
IL_008f: ret
} // end of method frmResearch::WithIfAndElse
Run Code Online (Sandbox Code Playgroud)
块#2
.method public hidebysig instance int64 WithOnlyIf(int32 myFlag) cil managed
{
// Code size 142 (0x8e)
.maxstack 3
.locals init ([0] class [System]System.Diagnostics.Stopwatch myTimer,
[1] string someString,
[2] int32 i,
[3] string height,
[4] string width,
[5] string[] CS$0$0000)
IL_0000: newobj instance void [System]System.Diagnostics.Stopwatch::.ctor()
IL_0005: stloc.0
IL_0006: ldstr ""
IL_000b: stloc.1
IL_000c: ldloc.0
IL_000d: callvirt instance void [System]System.Diagnostics.Stopwatch::Start()
IL_0012: ldc.i4.0
IL_0013: stloc.2
IL_0014: br.s IL_006e
IL_0016: ldstr "80%"
IL_001b: stloc.3
IL_001c: ldstr "80%"
IL_0021: stloc.s width
IL_0023: ldarg.1
IL_0024: ldc.i4.1
IL_0025: bne.un.s IL_0034
IL_0027: ldstr "60%"
IL_002c: stloc.3
IL_002d: ldstr "60%"
IL_0032: stloc.s width
IL_0034: ldc.i4.5
IL_0035: newarr [mscorlib]System.String
IL_003a: stloc.s CS$0$0000
IL_003c: ldloc.s CS$0$0000
IL_003e: ldc.i4.0
IL_003f: ldstr "Height: "
IL_0044: stelem.ref
IL_0045: ldloc.s CS$0$0000
IL_0047: ldc.i4.1
IL_0048: ldloc.3
IL_0049: stelem.ref
IL_004a: ldloc.s CS$0$0000
IL_004c: ldc.i4.2
IL_004d: call string [mscorlib]System.Environment::get_NewLine()
IL_0052: stelem.ref
IL_0053: ldloc.s CS$0$0000
IL_0055: ldc.i4.3
IL_0056: ldstr "Width: "
IL_005b: stelem.ref
IL_005c: ldloc.s CS$0$0000
IL_005e: ldc.i4.4
IL_005f: ldloc.s width
IL_0061: stelem.ref
IL_0062: ldloc.s CS$0$0000
IL_0064: call string [mscorlib]System.String::Concat(string[])
IL_0069: stloc.1
IL_006a: ldloc.2
IL_006b: ldc.i4.1
IL_006c: add
IL_006d: stloc.2
IL_006e: ldloc.2
IL_006f: ldc.i4 0xf4240
IL_0074: blt.s IL_0016
IL_0076: ldloc.0
IL_0077: callvirt instance void [System]System.Diagnostics.Stopwatch::Stop()
IL_007c: ldstr "testif.txt"
IL_0081: ldloc.1
IL_0082: call void [mscorlib]System.IO.File::WriteAllText(string,
string)
IL_0087: ldloc.0
IL_0088: callvirt instance int64 [System]System.Diagnostics.Stopwatch::get_ElapsedMilliseconds()
IL_008d: ret
} // end of method frmResearch::WithOnlyIf
Run Code Online (Sandbox Code Playgroud)
所以我们可以说IF-Else块(块#1)比if块(块#2)运行得更快,正如本论坛中许多人所指出的那样.
Ian*_*oyd 93
第1块的 10,000,000次迭代
myFlag = 0: 23.8ns per iteration
myFlag = 1: 23.8ns per iteration
Run Code Online (Sandbox Code Playgroud)
第2块的 10,000,000次迭代
myFlag = 0: 23.8ns per iteration
myFlag = 1: 46.8ns per iteration
Run Code Online (Sandbox Code Playgroud)
块2比块1慢96%.有道理,因为Block 2在悲观情况下做了两倍的工作.
我更喜欢这两种情况,视情况而定.如果
myFlag
是很少能 1,那么就希望它脱颖而出,我们必须处理的边缘情况.如果两者同样可能,我想要if-else
语法.但这是偏好,而不是事实.
几十年前,如果采取条件跳转,英特尔80286双管道将停止,而不是落入下一条指令.到奔腾的时候消失了; CPU预取两个分支路径.但是在我的脑海里,每当我编写具有该else
条款中最常见结果的代码时,我仍然会有一丝恐惧.每当我不得不提醒自己,这不再重要.
Int32 reps = 10000000;
private void Block1(int myFlag)
{
String width;
String height;
Stopwatch sw = new Stopwatch();
sw.Start();
for (int i = 0; i < reps; i++)
{
if (myFlag == 1)
{
width = String.Format("{0:g}%", 60);
height = String.Format("{0:g}%", 60);
}
else
{
width = String.Format("{0:g}%", 80);
height = String.Format("{0:g}%", 80);
}
}
sw.Stop();
Double time = (Double)sw.Elapsed.Ticks / Stopwatch.Frequency * 1000000000.0 / reps;
MessageBox.Show(time.ToString() + " ns");
}
private void Block2(int myFlag)
{
String width;
String height;
Stopwatch sw = new Stopwatch();
sw.Start();
for (int i = 0; i < reps; i++)
{
width = String.Format("{0:g}%", 80);
height = String.Format("{0:g}%", 80);
if (myFlag == 1)
{
width = String.Format("{0:g}%", 60);
height = String.Format("{0:g}%", 60);
}
}
sw.Stop();
Double time = (Double)sw.Elapsed.Ticks / Stopwatch.Frequency * 1000000000.0 / reps;
MessageBox.Show(time.ToString() + " ns");
}
Run Code Online (Sandbox Code Playgroud)
String.Format
使IF
慢96%GetPercentageString(0.60)
使IF
慢96%const
reps = 10000000;
procedure Block1(myflag: Integer);
var
width, height: string;
i: Integer;
t1, t2: Int64;
time: Extended;
freq: Int64;
begin
QueryPerformanceCounter(t1);
for i := 1 to reps do
begin
if myFlag = 1 then
begin
width := '60%';
height := '60%';
end
else
begin
width := '80%';
height := '80%';
end;
end;
QueryPerformanceCounter(t2);
QueryPerformanceFrequency(freq);
time := (t2-t1) / freq * 1000000000 / reps;
ShowMessage(FloatToStr(time)+ 'ns');
end;
procedure Block2(myflag: Integer);
var
width, height: string;
i: Integer;
t1, t2: Int64;
time: Extended;
freq: Int64;
begin
QueryPerformanceCounter(t1);
for i := 1 to reps do
begin
width := '80%';
height := '80%';
if myFlag = 1 then
begin
width := '60%';
height := '60%';
end;
end;
QueryPerformanceCounter(t2);
QueryPerformanceFrequency(freq);
time := (t2-t1) / freq * 1000000000 / reps;
ShowMessage(FloatToStr(time)+ 'ns');
end;
Run Code Online (Sandbox Code Playgroud)
做两倍的工作量大约是时间的两倍.
答:IF的表现不如IF-ELSE.
Joe*_*ton 45
这里的性能提升可以忽略不计,我称之为微微观微优化.除非你计划这样做几百万次,否则请在这里阅读.
编辑:(重新:评论中的问题)
在我看来,第一个是更可读的.它以准备好的格式明确地显示了每种情况下字符串应该是什么.第二个省略了一个案例,因此审阅者必须查看代码的其他区域以确定默认值.为了正确看待它,想象一下原始声明/初始化和这个特定代码块之间的50行代码.如果在那种情况下变得不清楚那么那将由我来决定.
Vam*_*msi 13
更新
根据Matthew Steeples根据Lou Franco 回答和测试Release版本中的代码更新代码后,我发现If-Else blcoks的性能优于if块,尽管略有不同
我在测试应用程序中使用了以下代码块
C#.net代码
块#1
public long WithIfAndElse(int myFlag)
{
Stopwatch myTimer = new Stopwatch();
string someString = "";
myTimer.Start();
for (int i = 0; i < 1000000; i++)
{
string height;
string width;
if (myFlag == 1)
{
height = "60%";
width = "60%";
}
else
{
height = "80%";
width = "80%";
}
someString = "Height: " + height + Environment.NewLine + "Width: " + width;
}
myTimer.Stop();
File.WriteAllText("testifelse.txt", someString);
return myTimer.ElapsedMilliseconds;
}
Run Code Online (Sandbox Code Playgroud)
块#2
public long WithOnlyIf(int myFlag)
{
Stopwatch myTimer = new Stopwatch();
string someString = "";
myTimer.Start();
for (int i = 0; i < 1000000; i++)
{
string height = "80%";
string width = "80%";
if (myFlag == 1)
{
height = "60%";
width = "60%";
}
someString = "Height: " + height + Environment.NewLine + "Width: " + width;
}
myTimer.Stop();
File.WriteAllText("testif.txt", someString);
return myTimer.ElapsedMilliseconds;
}
Run Code Online (Sandbox Code Playgroud)
以下是发布版本的结果
结果为1000000次迭代
块#1
myFlag = 1: 1688 Milliseconds
myFlag = 0: 1664 Milliseconds
Run Code Online (Sandbox Code Playgroud)
块#2
myFlag = 1: 1700 Milliseconds
myFlag = 0: 1677 Milliseconds
Run Code Online (Sandbox Code Playgroud)
IL代码由ildasm.exe生成
块#1
.method public hidebysig instance int64 WithIfAndElse(int32 myFlag) cil managed
{
// Code size 144 (0x90)
.maxstack 3
.locals init ([0] class [System]System.Diagnostics.Stopwatch myTimer,
[1] string someString,
[2] int32 i,
[3] string height,
[4] string width,
[5] string[] CS$0$0000)
IL_0000: newobj instance void [System]System.Diagnostics.Stopwatch::.ctor()
IL_0005: stloc.0
IL_0006: ldstr ""
IL_000b: stloc.1
IL_000c: ldloc.0
IL_000d: callvirt instance void [System]System.Diagnostics.Stopwatch::Start()
IL_0012: ldc.i4.0
IL_0013: stloc.2
IL_0014: br.s IL_0070
IL_0016: ldarg.1
IL_0017: ldc.i4.1
IL_0018: bne.un.s IL_0029
IL_001a: ldstr "60%"
IL_001f: stloc.3
IL_0020: ldstr "60%"
IL_0025: stloc.s width
IL_0027: br.s IL_0036
IL_0029: ldstr "80%"
IL_002e: stloc.3
IL_002f: ldstr "80%"
IL_0034: stloc.s width
IL_0036: ldc.i4.5
IL_0037: newarr [mscorlib]System.String
IL_003c: stloc.s CS$0$0000
IL_003e: ldloc.s CS$0$0000
IL_0040: ldc.i4.0
IL_0041: ldstr "Height: "
IL_0046: stelem.ref
IL_0047: ldloc.s CS$0$0000
IL_0049: ldc.i4.1
IL_004a: ldloc.3
IL_004b: stelem.ref
IL_004c: ldloc.s CS$0$0000
IL_004e: ldc.i4.2
IL_004f: call string [mscorlib]System.Environment::get_NewLine()
IL_0054: stelem.ref
IL_0055: ldloc.s CS$0$0000
IL_0057: ldc.i4.3
IL_0058: ldstr "Width: "
IL_005d: stelem.ref
IL_005e: ldloc.s CS$0$0000
IL_0060: ldc.i4.4
IL_0061: ldloc.s width
IL_0063: stelem.ref
IL_0064: ldloc.s CS$0$0000
IL_0066: call string [mscorlib]System.String::Concat(string[])
IL_006b: stloc.1
IL_006c: ldloc.2
IL_006d: ldc.i4.1
IL_006e: add
IL_006f: stloc.2
IL_0070: ldloc.2
IL_0071: ldc.i4 0xf4240
IL_0076: blt.s IL_0016
IL_0078: ldloc.0
IL_0079: callvirt instance void [System]System.Diagnostics.Stopwatch::Stop()
IL_007e: ldstr "testifelse.txt"
IL_0083: ldloc.1
IL_0084: call void [mscorlib]System.IO.File::WriteAllText(string,
string)
IL_0089: ldloc.0
IL_008a: callvirt instance int64 [System]System.Diagnostics.Stopwatch::get_ElapsedMilliseconds()
IL_008f: ret
} // end of method frmResearch::WithIfAndElse
Run Code Online (Sandbox Code Playgroud)
块#2
.method public hidebysig instance int64 WithOnlyIf(int32 myFlag) cil managed
{
// Code size 142 (0x8e)
.maxstack 3
.locals init ([0] class [System]System.Diagnostics.Stopwatch myTimer,
[1] string someString,
[2] int32 i,
[3] string height,
[4] string width,
[5] string[] CS$0$0000)
IL_0000: newobj instance void [System]System.Diagnostics.Stopwatch::.ctor()
IL_0005: stloc.0
IL_0006: ldstr ""
IL_000b: stloc.1
IL_000c: ldloc.0
IL_000d: callvirt instance void [System]System.Diagnostics.Stopwatch::Start()
IL_0012: ldc.i4.0
IL_0013: stloc.2
IL_0014: br.s IL_006e
IL_0016: ldstr "80%"
IL_001b: stloc.3
IL_001c: ldstr "80%"
IL_0021: stloc.s width
IL_0023: ldarg.1
IL_0024: ldc.i4.1
IL_0025: bne.un.s IL_0034
IL_0027: ldstr "60%"
IL_002c: stloc.3
IL_002d: ldstr "60%"
IL_0032: stloc.s width
IL_0034: ldc.i4.5
IL_0035: newarr [mscorlib]System.String
IL_003a: stloc.s CS$0$0000
IL_003c: ldloc.s CS$0$0000
IL_003e: ldc.i4.0
IL_003f: ldstr "Height: "
IL_0044: stelem.ref
IL_0045: ldloc.s CS$0$0000
IL_0047: ldc.i4.1
IL_0048: ldloc.3
IL_0049: stelem.ref
IL_004a: ldloc.s CS$0$0000
IL_004c: ldc.i4.2
IL_004d: call string [mscorlib]System.Environment::get_NewLine()
IL_0052: stelem.ref
IL_0053: ldloc.s CS$0$0000
IL_0055: ldc.i4.3
IL_0056: ldstr "Width: "
IL_005b: stelem.ref
IL_005c: ldloc.s CS$0$0000
IL_005e: ldc.i4.4
IL_005f: ldloc.s width
IL_0061: stelem.ref
IL_0062: ldloc.s CS$0$0000
IL_0064: call string [mscorlib]System.String::Concat(string[])
IL_0069: stloc.1
IL_006a: ldloc.2
IL_006b: ldc.i4.1
IL_006c: add
IL_006d: stloc.2
IL_006e: ldloc.2
IL_006f: ldc.i4 0xf4240
IL_0074: blt.s IL_0016
IL_0076: ldloc.0
IL_0077: callvirt instance void [System]System.Diagnostics.Stopwatch::Stop()
IL_007c: ldstr "testif.txt"
IL_0081: ldloc.1
IL_0082: call void [mscorlib]System.IO.File::WriteAllText(string,
string)
IL_0087: ldloc.0
IL_0088: callvirt instance int64 [System]System.Diagnostics.Stopwatch::get_ElapsedMilliseconds()
IL_008d: ret
} // end of method frmResearch::WithOnlyIf
Run Code Online (Sandbox Code Playgroud)
Lou*_*nco 11
您可以使用性能分析器自己回答这个问题,或者只是计时(将函数放在您多次调用的循环中).如您所知,编译器将其转换为相同的代码(您可以检查)
可能你不应该担心这些微优化.编写最易读的代码,直到您的工具告诉您要优化的内容.
如前所述,如果您对可读性感兴趣,那么性能可能不会成为问题,尽管您可能想要尝试以下方法:
string height = StdHeight;
string width = StdWidth;
if (restrictDimensionsFlag)
{
height = RestrictedHeight;
width = RestrictedWidth;
}
Run Code Online (Sandbox Code Playgroud)
并将std和受限大小定义为其他地方的consts或readonlys(或从config中读取).
归档时间: |
|
查看次数: |
3150 次 |
最近记录: |