【问题标题】:Slow While loop in C#C#中的慢while循环
【发布时间】:2012-07-18 22:46:55
【问题描述】:

我有一个while 循环,它所做的只是一个方法调用。我在循环外部有一个计时器,另一个计时器递增地增加方法调用在循环内花费的时间。外部时间大约需要 17 秒,内部计时器的总时间为 40 毫秒。该循环正在执行 50,000 次。下面是代码示例:

long InnerTime = 0;
long OutterTime = 0;
Stopw1.Start();
int count = 1;
while (count <= TestCollection.Count) {
    Stopw2.Start();
    Medthod1();
    Stopw2.Stop();
    InnerTime = InnerTime + Stopw2.ElapsedMilliseconds;
    Stopw2.Reset();
    count++;
}
Stopw1.Stop();
OutterTime = Stopw1.ElapsedMilliseconds;
Stopw1.Reset();

任何帮助将不胜感激。 马西莫

【问题讨论】:

  • 你有没有试过去掉内循环计时码,看看它是否加快了速度?
  • 代码似乎很好,除了“Method1”,我们不知道它是做什么的。否则,关于计时器似乎一切正常!
  • 什么是TestCollection - 它是一种方法、变量/属性还是什么?尝试将TestCollection.Count 替换为一个常数(显然是一个低到不会跌倒的值)。
  • 尝试在循环外执行 int countLimit = TestCollection.Count 并在您的条件下使用 countLimit。如果集合是高度动态的,这可能是一个非常昂贵的评估。
  • 如果 TestCollection 是 Collection 或 List 的实例,则 Count 是 O(1) 操作。除非它是某种低效的自定义类,否则不会导致问题。

标签: c# performance loops while-loop


【解决方案1】:

你在比较苹果和橘子。您的外部计时器测量所用的总时间。您的内部计时器测量调用Method1 所用的 毫秒数。

ElapsedMilliseconds 属性“表示经过的时间,向下舍入到最接近的整数毫秒值。”因此,您将 向下 舍入到最接近的毫秒,大约 50,000 次。

如果您对Method1 的调用平均花费不到 1 毫秒,那么在大多数情况下,`ElapsedMilliseconds' 属性将返回 0,而您的内部计数将大大少于实际时间。事实上,你的方法平均需要大约 0.3 毫秒,所以你很幸运,甚至可以让它超过 1 毫秒 40 次。

使用Elapsed.TotalMillisecondsElapsedTicks 属性而不是ElapsedMilliseconds。一毫秒相当于 10,000 个滴答声。

【讨论】:

  • 使用 ElapsedTicks 可以更准确地反映时间。结果只有 72 毫秒的时间差。谢谢 Jeffrey
【解决方案2】:

这是在做什么:TestCollection.Count

我怀疑你的 17 秒是在一遍又一遍地计算你的 50,000 件物品上。

【讨论】:

  • 你认为它是在计算 50,000 次? TestCollection 的类型会很有趣。
  • 您可能想到的是 Linq Count() 表达式,而不是 ICollection.Count 属性。
【解决方案3】:

尝试改变这个:

while (count <= TestCollection.Count) {
...
}

到这里:

int total = TestCollection.Count;
while (count <= total) {
...
}

【讨论】:

    【解决方案4】:

    为了补充其他人已经说过的内容,通常 C# 编译器必须重新评估任何属性,包括

    TestCollection.Count
    

    对于每一个循环迭代。属性的值可能会随着迭代而变化。

    将值分配给局部变量,编译器无需为每次循环迭代重新计算。

    我知道的一个例外是 Array.Length,它受益于专门针对数组的优化。这称为Array Bounds Check Elimination

    【讨论】:

    • ICollection.Count 通常只返回一个私有字段值。尽管价值可能会改变并导致问题,但我认为“重新评估房产”不是问题。
    • 当然,我认为真正的问题是他没有像@Jeffrey 指出的那样正确测量。只是为了完整性而添加了这个。有时属性评估相对于循环体来说是昂贵的(只是不在这里)。
    【解决方案5】:

    要正确衡量通话所用的时间, 你应该使用蜱

    请尝试以下方法:

    long InnerTime = 0;
    long OutterTime = 0;
    
    Stopwatch Stopw1 = new Stopwatch();
    Stopwatch Stopw2 = new Stopwatch();
    
    Stopw1.Start();
    int count = 1;
    int run = TestCollection.Count;
    while (count <= run) {
        Stopw2.Start();
        Medthod1();
        Stopw2.Stop();
        InnerTime = InnerTime + Stopw2.ElapsedTicks;
        Stopw2.Reset();
        count++;
    }
    Stopw1.Stop();
    OutterTime = Stopw1.ElapsedTicks;
    Stopw1.Reset();
    

    【讨论】:

      【解决方案6】:

      您不应该单独测量这种微小的方法。但如果你真的想,试试这个:

      long innertime = 0;
      
      while (count <= TestCollection.Count) 
      {     
          innertime -= Stopw2.GetTimestamp();
          Medthod1();
          innertime += Stopw2.GetTimestamp();
          count++; 
      } 
      
      Console.WriteLine("{0} ms", innertime * 1000.0 / Stopw2.Frequency);
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2012-11-11
        • 2022-01-21
        • 1970-01-01
        • 2016-07-12
        相关资源
        最近更新 更多