【问题标题】:why foreach is faster than for loop while reading richtextbox lines为什么在读取richtextbox行时foreach比for循环快
【发布时间】:2010-11-11 07:56:55
【问题描述】:

从RichTextBox逐行读取数据有两种方式

1 ) 使用 for 循环遍历 RichtextBox 的行

String s=String.Empty;
for(int i=0;i<richtextbox.lines.length;i++)
 {
     s=richTextBox.Lines[i]
 }

2 ) 使用 foreach 循环枚举richTextBox.Lines 集合

   String s=String.Empty;
   foreach(string str in txtText.Lines)
    {
       s=str;
    }

当我们使用foreach循环为richtextbox枚举数组集合时,性能存在巨大差异。

我尝试了 15000 行。for 循环花了 8 分钟才循环到 15000 行。而 foreach 花了几分之一秒来枚举它。

为什么会有这种行为?

【问题讨论】:

    标签: richtextbox


    【解决方案1】:

    正如 Mehrdad 所说,访问 Lines 属性需要很长时间。您需要在这里小心 - 您目前在每次迭代中访问它两次:

    String s = String.Empty;
    for (int i = 0; i < richTextBox.Lines.Length; i++)
    {
        s = richTextBox.Lines[i];
    }
    

    即使您像这样删除循环主体中的访问权限:

    String s = String.Empty;
    for (int i = 0; i < richTextBox.Lines.Length; i++)
    {
    }
    

    您仍然在每次迭代中访问Lines 以查看您是否已完成!

    如果你不想foreach,你可以只取一次Lines:

    string[] lines = richTextBox.Lines;
    for (int i = 0; i < lines.Length; i++)
    {
        s = lines[i];
    }
    

    我个人更喜欢foreach,除非你真的需要索引:)

    【讨论】:

    • 如果访问两次是问题,那么它不应该只花费两倍的时间。但他的差距是 8 分钟对几分之一秒。
    • @barlop:不,不是一次或两次的区别,而是一次和一次的区别。
    【解决方案2】:

    我认为Lines 属性在您每次想要访问它时都会重新计算。因此,foreach 方法只执行一次计算,而每次引用 Lines[i] 时,它都会重新评估整个事情。尝试缓存Lines 属性的结果并再次检查:

    String s = String.Empty;
    var lines = richtextbox.Lines;
    for(int i = 0; i < lines.Length; i++)
    {
        s = lines[i];
    }
    

    顺便说一句,您的问题隐含地假设foreach 总是比for 慢。这并不总是正确的。

    【讨论】:

    • 但是为什么使用 foreach 这么快。
    • foreach 将转换为对Lines 属性的一次调用。它调用GetEnumerator() 并仅使用生成的枚举器。 Lines 属性不再被调用。
    • +1 继承自 TextBoxBase 的 Lines 属性读取 Text 属性并逐个字符地遍历它,将它们拆分为行。调用 30k 次(15k 循环,两次检查长度和读取值)将比调用一次慢。
    • WinForms 充满了非 O(1) 属性。这些事情真的应该是IMO的方法。将它们设置为属性可能会导致在寻找性能错误时令人头疼。
    • 有没有办法在 for 和 foreach 循环之间进行选择。
    【解决方案3】:

    可能是因为在文本框中查找下一行需要时间。当您在第一种情况下通过索引使用随机访问时,它必须从头开始找到该行。当foreach内部完成迭代时,可以保持状态,快速找到下一行。

    这应该使第一个案例在 O(n^2) 时间内运行,而第二个案例在 O(n) 时间内运行。

    【讨论】:

    • 即使在删除“s=richTextBox.Lines[i]”之后,也花了那么多时间。我想知道只是迭代需要这么长时间。
    • 查看我的答案,了解为什么删除该行后仍然很慢。
    【解决方案4】:

    会不会是每行都在每个循环中被复制到一个新的字符串变量 (str) 中?我在这里伪装,但您可能可以使用此代码验证理论

    String s = String.Empty;
    for (int i = 0; i < richTextBox.Lines.Length; i++)
    {
        string str = richTextBox.Lines[i];
        s = str;
    }
    

    【讨论】:

    • 不,恐怕这与它无关。对变量的赋值实际上是免费的。
    【解决方案5】:

    .NET Reflector 非常有用,可以确定为什么您会看到出乎意料的性能。

    试试看Linesget访问器,看看每次访问它时它的实际作用。

    【讨论】:

      猜你喜欢
      • 2013-09-21
      • 2021-10-01
      • 2015-11-27
      • 1970-01-01
      • 1970-01-01
      • 2012-04-26
      • 2014-01-21
      • 1970-01-01
      • 2022-06-12
      相关资源
      最近更新 更多