以下3个示例代码是完全相同的,除了微小的差异,请在此处查看。然而速度差别很大。
示例1:在我的电脑中运行59秒。
namespace AoDtest
{
class Program
{
static bool IsWin(IList<string[]> slotView)
{
string[] symbol = new string[3];
for (int reelID = 0; reelID < 3; reelID++)
{
symbol[reelID] = slotView[reelID][1];
}
if (symbol.Contains("B")) return true; // Look at here
// if (symbol.Any(x => x == "B")) return true;
return false;
}
static void Main(string[] args)
{
Stopwatch watch = new Stopwatch();
watch.Start();
int count = 0;
string reel1 = "J K 10 S R 10 K Q 10 A Q K 10 Q K R 10 K R 10 J R 10 A Q R A 10 J Q 10 R K 10 L S A L 10 Q A S Q A R 10 K R L 10 R A S 10 L Q A L 10 S R 10 Q";
string reel2 = "L K J B A 10 Q L R Q J L Q R J Q 10 J R L Q J 10 B Q K 10 L Q J S Q 10 L A Q L J R Q 10 S A 10 Q B J A L S K Q S J 10 Q L S Q L K 10 R";
string reel3 = "J S A J B Q K J S 2x R Q S J R L J S K L J K L S J 10 B K Q S J K L A K J A K S 10 J A R 2x L K J A B K J R K J A K J A L R J K R";
string[] myreel1 = reel1.Split('\t');
string[] myreel2 = reel2.Split('\t');
string[] myreel3 = reel3.Split('\t');
for (int n = 0; n < 200; n++)
{
for (int i = 0; i < myreel1.Length; i++)
for (int j = 0; j < myreel2.Length; j++)
for (int k = 0; k < myreel3.Length; k++)
{
string[][] slotView = new string[3][];
for (int m = 0; m < 3; m++)
{
slotView[m] = new string[2];
}
slotView[0][1] = myreel1[i];
slotView[1][1] = myreel2[j];
slotView[2][1] = myreel3[k];
if (IsWin(slotView)) count++;
}
}
watch.Stop();
Console.WriteLine(count);
Console.WriteLine((double)reel1.Length * reel2.Length * reel3.Length / count);
Console.WriteLine(watch.Elapsed);
}
}
}
示例2:它在我的电脑中占据了20秒。
namespace AoDtest
{
class Program
{
static bool IsWin(IList<string[]> slotView)
{
string[] symbol = new string[3];
for (int reelID = 0; reelID < 3; reelID++)
{
symbol[reelID] = slotView[reelID][1];
}
// if (symbol.Contains("B")) return true;
if (symbol.Any(x => x == "B")) return true; // Look at here
return false;
}
static void Main(string[] args)
{
Stopwatch watch = new Stopwatch();
watch.Start();
int count = 0;
string reel1 = "J K 10 S R 10 K Q 10 A Q K 10 Q K R 10 K R 10 J R 10 A Q R A 10 J Q 10 R K 10 L S A L 10 Q A S Q A R 10 K R L 10 R A S 10 L Q A L 10 S R 10 Q";
string reel2 = "L K J B A 10 Q L R Q J L Q R J Q 10 J R L Q J 10 B Q K 10 L Q J S Q 10 L A Q L J R Q 10 S A 10 Q B J A L S K Q S J 10 Q L S Q L K 10 R";
string reel3 = "J S A J B Q K J S 2x R Q S J R L J S K L J K L S J 10 B K Q S J K L A K J A K S 10 J A R 2x L K J A B K J R K J A K J A L R J K R";
string[] myreel1 = reel1.Split('\t');
string[] myreel2 = reel2.Split('\t');
string[] myreel3 = reel3.Split('\t');
for (int n = 0; n < 200; n++)
{
for (int i = 0; i < myreel1.Length; i++)
for (int j = 0; j < myreel2.Length; j++)
for (int k = 0; k < myreel3.Length; k++)
{
string[][] slotView = new string[3][];
for (int m = 0; m < 3; m++)
{
slotView[m] = new string[2];
}
slotView[0][1] = myreel1[i];
slotView[1][1] = myreel2[j];
slotView[2][1] = myreel3[k];
if (IsWin(slotView)) count++;
}
}
watch.Stop();
Console.WriteLine(count);
Console.WriteLine((double)reel1.Length * reel2.Length * reel3.Length / count);
Console.WriteLine(watch.Elapsed);
}
}
}
示例3:现在我再次使用Contains()
,但将一些代码从IsWin
移到Main
,它现在运行14秒,为什么它在这里更快?
大发现:IList<string> symbol
如果我切换到string[] symbol
,则会运行57秒。
namespace AoDtest
{
class Program
{
static bool IsWin(IList<string> symbol)
{
if (symbol.Contains("B")) return true;
// if (symbol.Any(x => x == "B")) return true;
return false;
}
static void Main(string[] args)
{
Stopwatch watch = new Stopwatch();
watch.Start();
int count = 0;
string reel1 = "J K 10 S R 10 K Q 10 A Q K 10 Q K R 10 K R 10 J R 10 A Q R A 10 J Q 10 R K 10 L S A L 10 Q A S Q A R 10 K R L 10 R A S 10 L Q A L 10 S R 10 Q";
string reel2 = "L K J B A 10 Q L R Q J L Q R J Q 10 J R L Q J 10 B Q K 10 L Q J S Q 10 L A Q L J R Q 10 S A 10 Q B J A L S K Q S J 10 Q L S Q L K 10 R";
string reel3 = "J S A J B Q K J S 2x R Q S J R L J S K L J K L S J 10 B K Q S J K L A K J A K S 10 J A R 2x L K J A B K J R K J A K J A L R J K R";
string[] myreel1 = reel1.Split('\t');
string[] myreel2 = reel2.Split('\t');
string[] myreel3 = reel3.Split('\t');
for (int n = 0; n < 200; n++)
{
for (int i = 0; i < myreel1.Length; i++)
for (int j = 0; j < myreel2.Length; j++)
for (int k = 0; k < myreel3.Length; k++)
{
string[][] slotView = new string[3][];
for (int m = 0; m < 3; m++)
{
slotView[m] = new string[2];
}
slotView[0][1] = myreel1[i];
slotView[1][1] = myreel2[j];
slotView[2][1] = myreel3[k];
string[] symbol = new string[3];
for (int reelID = 0; reelID < 3; reelID++)
{
symbol[reelID] = slotView[reelID][1]; // Look at here
}
if (IsWin(symbol))
{
count++;
}
}
}
watch.Stop();
Console.WriteLine(count);
Console.WriteLine((double)reel1.Length * reel2.Length * reel3.Length / count);
Console.WriteLine(watch.Elapsed);
}
}
}
样本4:与样本3类似,但使用Any
代替,运行17秒。
Big Discovery:IList<string> symbol
如果我切换到string[] symbol
,那么它会运行18秒。
namespace AoDtest
{
class Program
{
static bool IsWin(IList<string> symbol)
{
if (symbol.Contains("B")) return true;
// if (symbol.Any(x => x == "B")) return true;
return false;
}
static void Main(string[] args)
{
Stopwatch watch = new Stopwatch();
watch.Start();
int count = 0;
string reel1 = "J K 10 S R 10 K Q 10 A Q K 10 Q K R 10 K R 10 J R 10 A Q R A 10 J Q 10 R K 10 L S A L 10 Q A S Q A R 10 K R L 10 R A S 10 L Q A L 10 S R 10 Q";
string reel2 = "L K J B A 10 Q L R Q J L Q R J Q 10 J R L Q J 10 B Q K 10 L Q J S Q 10 L A Q L J R Q 10 S A 10 Q B J A L S K Q S J 10 Q L S Q L K 10 R";
string reel3 = "J S A J B Q K J S 2x R Q S J R L J S K L J K L S J 10 B K Q S J K L A K J A K S 10 J A R 2x L K J A B K J R K J A K J A L R J K R";
string[] myreel1 = reel1.Split('\t');
string[] myreel2 = reel2.Split('\t');
string[] myreel3 = reel3.Split('\t');
for (int n = 0; n < 200; n++)
{
for (int i = 0; i < myreel1.Length; i++)
for (int j = 0; j < myreel2.Length; j++)
for (int k = 0; k < myreel3.Length; k++)
{
string[][] slotView = new string[3][];
for (int m = 0; m < 3; m++)
{
slotView[m] = new string[2];
}
slotView[0][1] = myreel1[i];
slotView[1][1] = myreel2[j];
slotView[2][1] = myreel3[k];
string[] symbol = new string[3];
for (int reelID = 0; reelID < 3; reelID++)
{
symbol[reelID] = slotView[reelID][1]; // Look at here
}
if (IsWin(symbol))
{
count++;
}
}
}
watch.Stop();
Console.WriteLine(count);
Console.WriteLine((double)reel1.Length * reel2.Length * reel3.Length / count);
Console.WriteLine(watch.Elapsed);
}
}
}
答案 0 :(得分:3)
这很有趣。
IEnumerable<T>.Contains
的文档说,如果source参数实现了ICollection<T>
,那么它会调用ICollection<T>.Contains
。由于string[]
实现了ICollection<string>
,所以这就是所谓的。
Array
的{{1}}实施最终会调用ICollection<T>.Contains
。
如果您将代码更改为:
Array.IndexOf
执行速度与if (Array.IndexOf(symbol, "B"))
一样快。如果您将代码更改为:
Any
在我的测试中,调用if ((symbol as ICollection<string>).Contains("B"))
的速度是调用Array.IndexOf
的两倍。
我怀疑正在放慢速度的是symbol.Contains
必须决定每次通话是否会调用IEnumerable<T>.Contains
,或者做其他事情。 <{1}}被调用时,不必做出这个决定。
您可以使用此替换ICollection<T>.Contains
中的所有代码,这比上述任何一种代码更快,并且更加简单。
Any
然后,当然,您可以完全摆脱IsWin
方法并写入内循环:
static bool IsWin(IList<string[]> slotView)
{
return slotView.Any(s => s[1] == "B");
}
答案 1 :(得分:1)
方法“Contains”在应用相等运算符(==)之前进行检查。当您多次运行循环时,将对循环计数重复此检查。 如果是'Any',你已经决定使用==所以.Any很快。 见:http://msdn.microsoft.com/en-us/library/ms132407.aspx
在第三种情况下,编译器必须优化代码而不是进行方法调用(而是在条件时写入签入)。
答案 2 :(得分:1)
您正在测量JIT编译器编译IsWin()方法所需的时间。这就是为什么当你将代码移到Main()中时它会产生如此大的差异,Main方法在开始你的秒表之前就会被引入。
通过重复测试体至少10次,使测量更有意义,这样您就可以消除抖动和缓存效果。这本身就有点危险,你的实际代码当然也会看到这些效果。