繁体   English   中英

添加秒表会导致 C# 性能损失?

[英]C# Performance Penalty from Adding Stop Watch?

将 C# Stop Watch 添加到对象会导致什么性能损失?

在 C# 编程的上下文中不应该那么重要。 如果证明它很重要,请重新考虑您对秒表和 C# 的需要/使用。

您始终可以尝试通过实施 1000 次、计时,然后将结果除以 1000 来自己进行基准测试。很难准确说明此功能对性能的要求有多高,但您可以将其与其他一些简单操作进行比较,看看效果如何它涉及到。

由于我希望在对象创建池中使用一些计时统计信息来即时优化其性能,因此我需要知道添加Stopwatch来监控计时是否会对对象创建的性能产生不利影响。 我想为典型的对象创建计时(大约 20-30 毫秒)以优化创建它们的任务的超时时间,但Stopwatch是添加Stopwatch不会明显减慢循环速度。

所以我写了这个测试程序来分别对创建的开销、 Start()Stop()Stopwatch经过时间检索进行Stopwatch

using System;
using System.Diagnostics;

namespace SO9925598_Stopwatch_overhead
{
    class Program
    {
        private const int nLoops = 10000;
        private const double nLoopsDouble = nLoops;
        private const int waitTime = 2; //ms

        static void Main(string[] args)
        {
            Stopwatch stopwatchTimingTheTest = new Stopwatch();
            double frequencyConversionFactor = 1000.0 / Convert.ToDouble(Stopwatch.Frequency);  // ms per click
            Stopwatch stopwatchUnderTest;

            // Instantiation
            for (int i = 0; i < nLoops; i++)
            {
                stopwatchTimingTheTest.Start();
                stopwatchUnderTest = new Stopwatch();
                stopwatchTimingTheTest.Stop();
                stopwatchUnderTest = null;
            }
            long elapsed = stopwatchTimingTheTest.ElapsedTicks;
            double overhead = frequencyConversionFactor * (Convert.ToDouble(elapsed) / nLoopsDouble);
            Console.WriteLine($"Creation overhead {overhead} ms per Stopwatch instantiation. (Based on {nLoops} trials).");

            // Further tests can all use the same object
            stopwatchUnderTest = new Stopwatch();

            // Start
            stopwatchTimingTheTest.Reset();
            for (int i = 0; i < nLoops; i++)
            {
                stopwatchTimingTheTest.Start();
                stopwatchUnderTest.Start();
                stopwatchTimingTheTest.Stop();
                stopwatchUnderTest.Stop();
                elapsed = stopwatchUnderTest.ElapsedTicks;
            }
            elapsed = stopwatchTimingTheTest.ElapsedTicks;
            overhead = frequencyConversionFactor * (Convert.ToDouble(elapsed) / nLoopsDouble);
            Console.WriteLine($"Stopwatch.Start() overhead {overhead} ms.");

            // Stop
            stopwatchTimingTheTest.Reset();
            for (int i = 0; i < nLoops; i++)
            {
                stopwatchUnderTest.Start();
                stopwatchTimingTheTest.Start();
                stopwatchUnderTest.Stop();
                stopwatchTimingTheTest.Stop();
                elapsed = stopwatchUnderTest.ElapsedTicks;
            }
            elapsed = stopwatchTimingTheTest.ElapsedTicks;
            overhead = frequencyConversionFactor * (Convert.ToDouble(elapsed) / nLoopsDouble);
            Console.WriteLine($"Stopwatch.Stop() overhead {overhead} ms.");

            // Elapsed ticks
            stopwatchTimingTheTest.Reset();
            for (int i = 0; i < nLoops; i++)
            {
                stopwatchUnderTest.Start();
                stopwatchUnderTest.Stop();
                stopwatchTimingTheTest.Start();
                elapsed = stopwatchUnderTest.ElapsedTicks;
                stopwatchTimingTheTest.Stop();
            }
            elapsed = stopwatchTimingTheTest.ElapsedTicks;
            overhead = frequencyConversionFactor * (Convert.ToDouble(elapsed) / nLoopsDouble);
            Console.WriteLine($"Stopwatch.ElapsedTicks overhead {overhead} ms.");

            // Elapsed ticks
            stopwatchTimingTheTest.Reset();
            for (int i = 0; i < nLoops; i++)
            {
                stopwatchUnderTest.Start();
                stopwatchUnderTest.Stop();
                stopwatchTimingTheTest.Start();
                elapsed = stopwatchUnderTest.ElapsedMilliseconds;
                stopwatchTimingTheTest.Stop();
            }
            elapsed = stopwatchTimingTheTest.ElapsedTicks;
            overhead = frequencyConversionFactor * (Convert.ToDouble(elapsed) / nLoopsDouble);
            Console.WriteLine($"Stopwatch.ElapsedMilliseconds overhead {overhead} ms.");

            Console.WriteLine("Press any key to continue...");
            Console.ReadKey();
        }
    }
}

结果如下:

Creation overhead 0,00011756 ms per Stopwatch instantiation. (Based on 10000 trials).
Stopwatch.Start() overhead 0,000256 ms.
Stopwatch.Stop() overhead 0,00023665 ms.
Stopwatch.ElapsedTicks overhead 0,00010946 ms.
Stopwatch.ElapsedMilliseconds overhead 0,00011758 ms.

次数是基于 10000 个样本的方法每次调用的平均时间。

该程序运行在一台装有 Intel Core i7-8850H CPU 的机器上,频率为 2.60 GHz,装有 Windows 10 操作系统。

结论:对于对象创建时间为 20-30 毫秒的应用程序, Stopwatch的开销可以忽略不计。

  static void Main(string[] args)
        {
            Worker(1); // jit Warmup
            var stopWatchOfStopwatchStopwatch = System.Diagnostics.Stopwatch.StartNew();
            var stopWatchOfLoop = System.Diagnostics.Stopwatch.StartNew();
            Worker(100000000);
            stopWatchOfLoop.Stop();
            Console.WriteLine("Elapsed of inner SW: " + stopWatchOfLoop.Elapsed.ToString());
            stopWatchOfStopwatchStopwatch.Stop();
            Console.WriteLine("Elapsed of outer SW: " + stopWatchOfStopwatchStopwatch.Elapsed.ToString());

            var stopwatchOfcompareLoop = System.Diagnostics.Stopwatch.StartNew();
            Worker(100000000);
            stopwatchOfcompareLoop.Stop();
            Console.WriteLine("Elapsed of inner SW: " + stopWatchOfLoop.Elapsed.ToString());
        }
        static void Worker(int iterations)
        {
            for (int i = 0; i < iterations; i++)
            {
                Console.WriteLine("bla");
            }
        }

差异微不足道 - 但这在很大程度上取决于您的性能目标:)

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM