Почему foreach быстрее, чем для цикла при чтении строк richtextbox

Существует два способа чтения данных из 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 строк. Для цикла было занято 8 минут, чтобы просто выполнить цикл до 15000 строк. В то время как foreach взял долю секунды, чтобы перечислить его.

Почему такое поведение существует?

Ответ 1

Как отметил Мехрдад, доступ к свойству 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, если вам действительно нужен индекс:)

Ответ 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. Это не всегда так.

Ответ 3

Возможно, потому что для поиска следующей строки в текстовом поле требуется время. Когда вы используете случайный доступ путем индексации в первом случае, он должен найти эту строку с нуля. Когда итерация выполняется внутри foreach, она может сохранять состояние и быстро находить следующую строку.

Это должно сделать первый случай в O (n ^ 2), а второй - в O (n).

Ответ 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 очень полезно определить , почему вы видите производительность, чего вы не ожидаете.

Попробуйте посмотреть на аксессуар Lines get, чтобы узнать, что он на самом деле делает каждый раз, когда вы обращаетесь к нему.