c#性能和可能的优化
本文关键字:优化 性能 | 更新日期: 2023-09-27 18:16:28
我们在一个小的测试应用程序中有一个非常有趣的效果,我们无法解释。
我们有代码块:while (true)
{
for (int i = 0; i < 1920; i++)
{
for (int j = 0; j < 1080; j++)
{
//l += rand.Next(j);
l += matcher.Next(j);
}
}
k++;
Console.WriteLine("{0}: Iteration {1}, l: {2}", DateTime.Now.ToString("hh:mm:ss"), k, l);
l = 0;
handle.WaitOne(100);
}
类Matcher在它的Next(j)
调用中只做一件事。它返回其内部创建的随机对象的Next(j)
方法(因此,我们添加了一个简单的函数调用)。
这是Matcher类的定义:
class Matcher
{
private Random rand = new Random();
internal int Next(int j)
{
return rand.Next(j);
}
}
当我们执行这段代码时,在Intel Core 2 Quad上进行一次迭代大约需要6秒。但是,如果我们注释l += matcher.Next(j);
行并取消注释l += rand.Next(j);
行,则单次迭代将在第2秒左右开始。
有人知道为什么会这样吗?
这不仅仅是一个简单的函数调用,它也是内部rand对象的解引用,在那里发生。当你直接调用next random时,JIT编译器可以优化你的循环,但当它在另一个类中时,就不是这样了。
函数被调用超过2,000,000次,并且需要3微秒来计算。它不是世界上最快的函数,但也不是特别慢:是乘法效应杀死了性能。
如果matcher没有锁定,或者创建多个副本是可以的,你可以通过并行化你的算法来加速它,比如为你的Core2-Quad并行化8路。代码应该在一秒钟内完成
当然,额外的调用需要一些时间(简短的回答:p)。为什么是6倍还很难说。在查看性能时,最好查看生成的IL(例如,使用ILSpy),因为编译器可能会在一种情况下进行优化,而在另一种情况下可能无法进行优化。
最后一行c#可能会编译成不同的IL指令,甚至被翻译成不同的本机代码(所以在你的机器上运行得更快,但在另一台机器上运行得更慢)。在某些情况下,垃圾收集器甚至可能是造成差异的原因。
社区,非常感谢大家的帮助。问题是:我是从启用IntelliTrace的VS2010运行的:事件&;调用,而不仅仅是事件。这是一个简单的解释。
代码看起来不错。一定要在发布模式下运行它,因为这会产生很大的不同。此外,我甚至看到平台目标设置对某些低级操作有重大影响。所以请同时尝试x86和x64。
我已经把它设置为在"任何CPU"的发布模式下运行,并打开"优化代码",它在39毫秒内运行。