【问题标题】:Speed performance for recursion and iteration – Why do they both run at the same speed for different "small" numbers?递归和迭代的速度性能——为什么它们对于不同的“小”数都以相同的速度运行?
【发布时间】:2012-01-01 19:47:14
【问题描述】:

我正在尝试优化我拥有的代码。为了做到这一点,我编写了这段代码来查看递归与迭代的效果。代码“计数”到 10 的 n 次方。

public Form1()
{
    InitializeComponent();
    Stopwatch sw = new Stopwatch();
    sw.Start();
    recurse(4);
    //iterate(4);
    sw.Stop();
    Text = sw.Elapsed.TotalMilliseconds.ToString();
}

void recurse(int i)
{
    if (i < 1) return;
    for (int x = 0; x < 10; x++) recurse(i - 1);
}

void iterate(int i)
{
    i = (int)System.Math.Pow(10, i);
    for (int x = 0; x < i; x++) ;
}

我得到了这个意想不到的结果:当 n 为 1 到 4 时,递归和迭代的速度都在 0.5 毫秒左右。 - 而不是 4 比我预期的 1 慢 1000 倍。只有对于更大的数字,它才开始具有更直观的速度,迭代也比递归更快。

为什么10次和10000次的速度一样?

【问题讨论】:

  • Iterate 正在运行一个紧密的循环,而 recurse 正在执行一个循环中的调用。感觉这不是一个公平的比较。
  • 想想吧。这两种方法做了多少次迭代?他们有完全不同的时间复杂度......这个问题对我来说根本没有意义。
  • @rene 我的问题不是为什么递归更慢。我的问题是为什么 10 次和 10,000 次的速度相同。
  • @vidstige 我的问题不是为什么递归更慢。我的问题是为什么 10 次和 10,000 次的速度相同。

标签: c# performance


【解决方案1】:

即使您在两种情况下都更正了代码以计算相同的东西,也不要一次性测试类似的东西。除非测试本身至少需要一秒钟,否则您不会得到正确的结果。运行一百万次,然后除以总时间。当你测试只需要一两毫秒的东西时,你应该确保测试需要足够长的时间来忽略冷缓存的差异,.Start() 和 .Stop() 调用的时间,小的 GC 延迟同时等。还要确保实际工作比空计数循环花费更多的时间(即for(many times) recurse(x) 有足够高的x for 本身不相关)

单次运行 0.5 毫秒的结果在这里或多或少毫无意义。此外,如果它是一种 jitted 语言,我建议在测试之前调用相同的函数,以确保它已经编译 - 否则会增加开销。

TL;DR - 函数周围发生的其他事情的开销高于函数执行所需的时间。

【讨论】:

  • 谢谢。这可能是它。 span>
【解决方案2】:

我认为问题在于您的递归实现。除非我读错了,否则递归只运行 4 次,每次迭代 1 到 10 次。虽然迭代计算 10^4 - 10,000,然后从 0 计数到 10,000。

所以,你没有进行公平的比较。

修订:如果您确实在 0.5 毫秒范围内得到响应,那么您可能已经超出了所涉及函数的准确性。这篇 MS 文章 http://msdn.microsoft.com/en-us/library/system.diagnostics.stopwatch.aspx 提供了一个纳秒计时示例,您可能会觉得有帮助。这需要更多的工作,但可能会提供一些见解。

【讨论】:

  • a) 递归也运行 10,000 次。 b)我的问题不是为什么递归更慢。我的问题是为什么 10 次和 10,000 次的速度相同。
  • 我的立场是正确的,它确实迭代了正确的次数。
猜你喜欢
  • 2012-11-30
  • 2011-01-07
  • 2014-10-07
  • 2013-02-01
  • 2016-12-31
  • 1970-01-01
  • 2016-12-31
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多