Есть ли какие-либо возможные проблемы с производительностью для `foreach (var w в S.Split())` здесь?

#c#

#c#

Вопрос:

Учитывая фрагмент кода

 string S = "aa bb cc...";// very long string 
foreach(var w in S.Split()){// <-- how many invoke for Split() ?
                            // (Edited: After writing extension Method to test,
                            //it is invoked once.) 
    //do something
}
  

Есть ли какие-либо проблемы с производительностью для приведенного выше кода? Нужно ли мне переписать это, как показано ниже?

 string S = "aa bb cc...";
var strArray = S.Split();
foreach(var w in strArray){
    //do something
}

  

Комментарии:

1. ericlippert.com/2012/12/17/performance-rant

2. how many invoke for Split() ? Один.

3. Обе версии вашего кода будут работать одинаково.

4. Для такого рода вопросов всегда задавайте себе вопрос «как бы я это протестировал?» Вы могли бы, например, написать свою собственную Split2 функцию, поместить в нее точку останова, а затем посмотреть, сколько раз Split2 вызывается. И вы увидите, что ответ один.

5. Они фактически одинаковы, да.

Ответ №1:

Когда я компилирую обе версии вашего кода с включенной оптимизацией, я получаю тот же IL:

IL_0000: ldstr "aa bb cc ..."
IL_0005: вызов системы.Массив.Пусто
IL_000A: система callvirt.Строка.Разделение
IL_000F: stloc.0 
IL_0010: ldc.i4.0 
IL_0011: stloc.1 
IL_0012: br.s IL_001C
IL_0014: ldloc.0 
IL_0015: ldloc.1 
IL_0016: ldelem.ref 
IL_0017: pop 
IL_0018: ldloc.1 
IL_0019: ldc.i4.1 
IL_001A: добавить 
IL_001B: stloc.1 
IL_001C: ldloc.1 
IL_001D: ldloc.0 
IL_001E: ldlen 
IL_001F: conv.i4 
IL_0020: blt.s IL_0014
IL_0022: ret 

Между этими двумя версиями кода нет разницы (при оптимизации).

Ответ №2:

Оба фрагмента кода генерируют один и тот же код. Посмотрите на вывод декомпилятора (в данном случае ILSpy):

В конфигурации ОТЛАДКИ (без оптимизации кода);

 string s = "aa bb cc...";
// foreach (string w in s.Split())
string[] array = s.Split();
foreach (string w in array)
{
    Console.WriteLine(w);
}
  

и

 string s = "aa bb cc...";
// var stringArray = s.Split() ...
// foreach(var w in stringArray)
string[] stringArray = s.Split();
string[] array = stringArray;
foreach (string w in array)
{
    Console.WriteLine(w);
}
  

Итак, вы можете видеть, что второй фрагмент создаст еще одну ссылку на массив строк, что не должно иметь большого значения.

В режиме ВЫПУСКА (с оптимизацией кода) дополнительная ссылка ( array ) будет удалена, поэтому оба фрагмента генерируют тот же код, что и foreach (string w in s.Split())