【问题标题】:C#: struct constructor performanceC#:结构构造函数性能
【发布时间】:2017-07-25 09:15:02
【问题描述】:

为什么用构造函数创建结构比直接赋值慢? 在下面的代码中,我得到 10 秒的自定义构造函数和 6 秒没有!纯循环需要5秒。自定义构造函数比直接访问慢五 (!sic) 倍。

有什么技巧可以加快自定义构造函数的速度吗?

class Program
{
    public struct Point
    {
        public int x, y;

        public Point(int x, int y)
        {
            this.x = x;
            this.y = y;
        }
    }

    static void Main(string[] args)
    {
        Stopwatch sw = new Stopwatch();

        sw.Start();
        for(int i =0; i < int.MaxValue; i++)
        {
            var a = new Point(i, i);
        }
        sw.Stop();
        Console.WriteLine(sw.ElapsedMilliseconds);

        sw.Restart();
        for (int i = 0; i < int.MaxValue; i++)
        {
            var a = new Point();
            a.x = i;
            a.y = i;
        }
        sw.Stop();
        Console.WriteLine(sw.ElapsedMilliseconds);
        Console.ReadLine();
    }
}

【问题讨论】:

  • 你的分析是错误的。它不是慢 5 倍。您必须除以 int.MaxValue 才能进行高于相对速度的比较。构造函数调用您的自定义构造函数 Point() 方法,这需要额外的时间。调用应该非常小,但当 int.MaxValue 非常大时可能需要几秒钟。
  • 这些结果可能完全被 GC 时间扭曲了。尝试交换两个循环,看看会得到什么结果。
  • 还要确保您正在测试发布版本,并且您没有在调试器中运行它。
  • 简单循环需要 5 秒。使用自定义构造函数循环 10 秒。没有自定义构造函数的循环 6 秒。性能 = (10 - 5)/(6-5) ?

标签: c# struct constructor


【解决方案1】:

在下面的代码中,我使用自定义构造函数得到 10 秒

这不是需要 10 秒的代码,除非你有一台非常旧的机器。告诉我们您做错了什么,您正在运行未优化的 Debug 构建或在附加调试器的情况下运行。不允许内置在抖动中的优化器完成其工作的那种场景。

围绕代码循环运行 10 次,有助于摆脱启动开销和测量标准偏差,在这种非常快的代码上总是非常高。切换到 Release 版本并使用 Ctrl+F5 运行它。现在你得到了这段代码的真正性能,应该在 1.5 秒以南。这就是循环花费的时间,没有任何 Point 代码被优化器删除。它可以这样做是因为 a 变量没有在任何地方使用,并且构造函数没有可观察到的副作用。

完全删除您要分析的代码是典型的基准测试风险。您可以通过将a 变量提升出循环并使用以下方法来防止这种情况发生:

  Console.WriteLine("{0}", sw.ElapsedMilliseconds, a);

现在优化器无法再消除 Point 代码,因为该变量在循环之外使用。如果它仍然同样快,你就会知道你正在对它进行基准测试。你如何初始化结构并不重要。在this post 中详细了解抖动优化器的作用。

【讨论】:

  • 是的,这都是关于启用调试
【解决方案2】:

您的分析代码简化了很多事情,但它也使测量非常不准确。我建议使用BenchmarkDotNet 之类的工具来获得更准确的结果。

快速测试表明直接分配要快一些,但没有你声称的 5 倍:

[BenchmarkDotNet.Attributes.Benchmark(Baseline = true)]
public static Point GetPoint()
{
    return new Point(x, y);
}

[BenchmarkDotNet.Attributes.Benchmark]
public static Point GetPoint2()
{
    Point point = new Point();
    point.x = x;
    point.y = y;
    return point;
}
    Method |       Mean |    StdDev | Scaled | Scaled-StdDev |
---------- |----------- |---------- |------- |-------------- |
  GetPoint | 10.2038 ns | 0.2593 ns |   1.00 |          0.00 |
 GetPoint2 |  9.3272 ns | 0.0767 ns |   0.91 |          0.02 |

这是 10% 的差异,而不是 5 倍。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2010-11-10
    • 1970-01-01
    • 2012-02-27
    • 2022-12-16
    • 2012-03-08
    • 1970-01-01
    • 1970-01-01
    • 2017-06-10
    相关资源
    最近更新 更多