C# 中方法调用的基准测试

发布于 2024-08-09 02:00:51 字数 230 浏览 2 评论 0原文

我正在寻找一种方法来对 C# 中的方法调用进行基准测试。

我已经为大学作业编写了一个数据结构,并且只是想出了一种稍微优化的方法,但这种方法会在所有情况下增加一点开销,同时将 O(n) 调用变成 O(1)在一些。

现在我想针对测试数据运行这两个版本,看看是否值得实施优化。我知道在 Ruby 中,您可以将代码包装在 Benchmark 块中,并让它输出在控制台中执行该块所需的时间 - 有类似的东西可用于 C# 吗?

I'm looking for a way to benchmark method calls in C#.

I have coded a data structure for university assignment, and just came up with a way to optimize a bit, but in a way that would add a bit of overhead in all situations, while turning a O(n) call into O(1) in some.

Now I want to run both versions against the test data to see if it's worth implementing the optimization. I know that in Ruby, you could wrap the code in a Benchmark block and have it output the time needed to execute the block in console - is there something like that available for C#?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(6

静谧 2024-08-16 02:00:52

以下是我通过反复试验发现的一些事情。

  1. 丢弃第一批(数千次)迭代。他们很可能会受到 JITter 的影响。
  2. 在单独的 Thread 对象上运行基准测试可以提供更好、更稳定的结果。我不知道为什么。
  3. 我见过有些人在执行基准测试之前出于某种原因使用 Thread.Sleep 。这只会让事情变得更糟。我不知道为什么。可能是由于 JITter。
  4. 切勿在启用调试的情况下运行基准测试。该代码的运行速度很可能会慢几个数量级。
  5. 在启用所有优化的情况下编译您的应用程序。某些代码可能会受到优化的显着影响,而其他代码则不会,因此未经优化进行编译将影响基准测试的可靠性。
  6. 在启用优化的情况下进行编译时,有时需要以某种方式评估基准测试的输出(例如打印值等)。否则,编译器可能会“发现”某些计算是无用的,并且根本不会执行它们。
  7. 在执行某些基准测试时,委托的调用可能会产生明显的开销。最好在委托中放置多次迭代,这样开销对基准测试的结果影响很小。
  8. 分析器可能有自己的开销。他们擅长告诉您代码的哪些部分是瓶颈,但他们不擅长实际可靠地对两个不同的事物进行基准测试。
  9. 一般来说,花哨的基准测试解决方案可能会产生显着的开销。例如,如果您想使用一个接口对许多对象进行基准测试,则可能会将每个对象包装在一个类中。但是,请记住,类构造函数也有必须考虑的开销。最好让一切尽可能简单和直接。

Here are some things I've found by trial and errors.

  1. Discard the first batch of (thousands) iterations. They will most likely be affected by the JITter.
  2. Running the benchmark on a separate Thread object can give better and more stable results. I don't know why.
  3. I've seen some people using Thread.Sleep for whatever reason before executing the benchmark. This will only make things worse. I don't know why. Possibly due to the JITter.
  4. Never run the benchmark with debugging enabled. The code will most likely run orders of magnitude slower.
  5. Compile your application with all optimizations enabled. Some code can be drastically affected by optimization, while other code will not be, so compiling without optimization will affect the reliability of your benchmark.
  6. When compiling with optimizations enabled, it is sometimes necessary to somehow evaluate the output of the benchmark (e.g. print a value, etc). Otherwise the compiler may 'figure out' some computations are useless and will simply not perform them.
  7. Invocation of delegates can have noticeable overhead when performing certain benchmarks. It is better to put more than one iteration inside the delegate, so that the overhead has little effect on the result of the benchmark.
  8. Profilers can have their own overhead. They're good at telling you which parts of your code are bottlenecks, but they're not good at actually benchmarking two different things reliably.
  9. In general, fancy benchmarking solutions can have noticeable overhead. For example, if you want to benchmark many objects using one interface, it may be tempting to wrap every object in a class. However, remember that the class constructor also has overhead that must be taken into account. It is better to keep everything as simple and direct as possible.
风轻花落早 2024-08-16 02:00:52

您可以使用内置的 Stopwatch 类 来“提供您可以使用一组方法和属性来准确测量经过的时间。”如果您正在寻找手动方法来完成此操作。但不确定自动化。

You could use the inbuilt Stopwatch class to "Provides a set of methods and properties that you can use to accurately measure elapsed time." if you are looking for a manual way to do it. Not sure on automated though.

灼疼热情 2024-08-16 02:00:52

我从 Jon Skeet 的基准测试方法中窃取了以下大部分内容:

private static void Benchmark(Action act, int interval)
{
    GC.Collect();
    Stopwatch sw = Stopwatch.StartNew();
    for (int i = 0; i < interval; i++)
    {
        act.Invoke();
    }
    sw.Stop();
    Console.WriteLine(sw.ElapsedMilliseconds);
}

I stole most of the following from Jon Skeet's method for benchmarking:

private static void Benchmark(Action act, int interval)
{
    GC.Collect();
    Stopwatch sw = Stopwatch.StartNew();
    for (int i = 0; i < interval; i++)
    {
        act.Invoke();
    }
    sw.Stop();
    Console.WriteLine(sw.ElapsedMilliseconds);
}
枕花眠 2024-08-16 02:00:52

分析器提供了最好的基准,因为它们可以诊断您的所有代码,但是它们会减慢速度。分析器用于查找瓶颈。

为了优化算法,当您知道瓶颈在哪里时,请使用名称字典-->秒表,以跟踪运行时的性能关键部分。

Profilers give the best benchmarks since they diagnose all your code, however they slow it down a lot. Profilers are used for finding bottlenecks.

For optimizing an algorithm, when you know where the bottlenecks are, use a dictionary of name-->stopwatch, to keep track of the performance critical sections during run-time.

秋意浓 2024-08-16 02:00:52

听起来您想要一个分析器。我本人强烈推荐 EQATEC 分析器,它是我尝试过的最好的免费工具。与简单的秒表方法相比,这种方法的好处在于它还提供了某些方法/块的性能细分。

Sounds like you want a profiler. I would strongly recommend the EQATEC profiler myself, it being the best free one I've tried. The nice thing about this method over a simple stopwatch one is that it also provides a breakdown of performance over certain methods/blocks.

暮色兮凉城 2024-08-16 02:00:51

从 Yuriy 的答案中窃取(并修改):

private static void Benchmark(Action act, int iterations)
{
    GC.Collect();
    act.Invoke(); // run once outside of loop to avoid initialization costs
    Stopwatch sw = Stopwatch.StartNew();
    for (int i = 0; i < iterations; i++)
    {
        act.Invoke();
    }
    sw.Stop();
    Console.WriteLine((sw.ElapsedMilliseconds / iterations).ToString());
}

通常一个特定的方法必须初始化一些东西,并且您并不总是希望将这些初始化成本包含在总体基准中。此外,您还希望将总执行时间除以迭代次数,以便您的估计或多或少独立于迭代次数。

Stolen (and modified) from Yuriy's answer:

private static void Benchmark(Action act, int iterations)
{
    GC.Collect();
    act.Invoke(); // run once outside of loop to avoid initialization costs
    Stopwatch sw = Stopwatch.StartNew();
    for (int i = 0; i < iterations; i++)
    {
        act.Invoke();
    }
    sw.Stop();
    Console.WriteLine((sw.ElapsedMilliseconds / iterations).ToString());
}

Often a particular method has to initialize some things, and you don't always want to include those initialization costs in your overall benchmark. Also, you want to divide the total execution time by the number of iterations, so that your estimate is more-or-less independent of the number of iterations.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文