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秒左右开始。

有人知道为什么会这样吗?

c#性能和可能的优化

这不仅仅是一个简单的函数调用,它也是内部rand对象的解引用,在那里发生。当你直接调用next random时,JIT编译器可以优化你的循环,但当它在另一个类中时,就不是这样了。

函数被调用超过2,000,000次,并且需要3微秒来计算。它不是世界上最快的函数,但也不是特别慢:是乘法效应杀死了性能。

如果matcher没有锁定,或者创建多个副本是可以的,你可以通过并行化你的算法来加速它,比如为你的Core2-Quad并行化8路。代码应该在一秒钟内完成

当然,额外的调用需要一些时间(简短的回答:p)。为什么是6倍还很难说。在查看性能时,最好查看生成的IL(例如,使用ILSpy),因为编译器可能会在一种情况下进行优化,而在另一种情况下可能无法进行优化。

最后一行c#可能会编译成不同的IL指令,甚至被翻译成不同的本机代码(所以在你的机器上运行得更快,但在另一台机器上运行得更慢)。在某些情况下,垃圾收集器甚至可能是造成差异的原因。

社区,非常感谢大家的帮助。问题是:我是从启用IntelliTrace的VS2010运行的:事件&;调用,而不仅仅是事件。这是一个简单的解释。

代码看起来不错。一定要在发布模式下运行它,因为这会产生很大的不同。此外,我甚至看到平台目标设置对某些低级操作有重大影响。所以请同时尝试x86和x64。

我已经把它设置为在"任何CPU"的发布模式下运行,并打开"优化代码",它在39毫秒内运行。