实际上,尽管这里有一些评论,它可能会更快一些。
让我们实际测试一下:
using System;
using System.Diagnostics;
namespace Demo
{
class Program
{
static void Main(string[] args)
{
int count = 1000000000;
Stopwatch sw = Stopwatch.StartNew();
for (int way = 1; way <= 3; ++way)
test1(count, way);
var elapsed1 = sw.Elapsed;
Console.WriteLine("test1() took " + elapsed1);
sw.Restart();
for (int way = 1; way <= 3; ++way)
test2(count, way);
var elapsed2 = sw.Elapsed;
Console.WriteLine("test2() took " + elapsed2);
Console.WriteLine("test2() was {0:f1} times as fast.", + ((double)elapsed1.Ticks)/elapsed2.Ticks);
}
static void test1(int count, int way)
{
for (int i = 0; i < count; ++i)
{
switch (way)
{
case 1: doWork1(); break;
case 2: doWork2(); break;
case 3: doWork3(); break;
}
}
}
static void test2(int count, int way)
{
switch (way)
{
case 1:
for (int i = 0; i < count; ++i)
doWork1();
break;
case 2:
for (int i = 0; i < count; ++i)
doWork2();
break;
case 3:
for (int i = 0; i < count; ++i)
doWork3();
break;
}
}
static void doWork1()
{
}
static void doWork2()
{
}
static void doWork3()
{
}
}
}
现在这是非常不现实的,因为 doWork() 方法不做任何事情。但是,它将给我们一个基准时间。
在我的 Windows 7 x64 系统上构建 RELEASE 得到的结果是:
test1() took 00:00:03.8041522
test2() took 00:00:01.7916698
test2() was 2.1 times as fast.
因此,将循环移动到 switch 语句中可以使其速度快两倍。
现在让我们通过在 doWork() 中添加一些代码来让它更真实一点:
using System;
using System.Diagnostics;
namespace Demo
{
class Program
{
static void Main(string[] args)
{
int count = 1000000000;
Stopwatch sw = Stopwatch.StartNew();
for (int way = 1; way <= 3; ++way)
test1(count, way);
var elapsed1 = sw.Elapsed;
Console.WriteLine("test1() took " + elapsed1);
sw.Restart();
for (int way = 1; way <= 3; ++way)
test2(count, way);
var elapsed2 = sw.Elapsed;
Console.WriteLine("test2() took " + elapsed2);
Console.WriteLine("test2() was {0:f1} times as fast.", + ((double)elapsed1.Ticks)/elapsed2.Ticks);
}
static int test1(int count, int way)
{
int total1 = 0, total2 = 0, total3 = 0;
for (int i = 0; i < count; ++i)
{
switch (way)
{
case 1: doWork1(i, ref total1); break;
case 2: doWork2(i, ref total2); break;
case 3: doWork3(i, ref total3); break;
}
}
return total1 + total2 + total3;
}
static int test2(int count, int way)
{
int total1 = 0, total2 = 0, total3 = 0;
switch (way)
{
case 1:
for (int i = 0; i < count; ++i)
doWork1(i, ref total1);
break;
case 2:
for (int i = 0; i < count; ++i)
doWork2(i, ref total2);
break;
case 3:
for (int i = 0; i < count; ++i)
doWork3(i, ref total3);
break;
}
return total1 + total2 + total3;
}
static void doWork1(int n, ref int total)
{
total += n;
}
static void doWork2(int n, ref int total)
{
total += n;
}
static void doWork3(int n, ref int total)
{
total += n;
}
}
}
现在我得到这些结果:
test1() took 00:00:03.9153776
test2() took 00:00:05.3220507
test2() was 0.7 times as fast.
现在将循环放入开关变得更慢了!这种违反直觉的结果是这类事情的典型表现,并说明了为什么在尝试优化代码时应该始终执行时序测试。(并且像这样优化代码通常是你甚至不应该做的事情,除非你有充分的理由怀疑存在瓶颈。你最好花时间清理你的代码。;))
我做了一些其他测试,对于稍微简单的 doWork() 方法,test2() 方法更快。这在很大程度上取决于 JIT 编译器可以对优化做什么。
注意:我认为我的第二个测试代码的速度差异的原因是因为 JIT 编译器可以在内联对 doWork() 的调用时优化掉 'ref' 调用,当它们不在循环中时,如 test1() ; 而对于 test2() 它不能(出于某种原因)。