У меня был небольшой спор (который был очень близок к священной войне:)) с моим коллегой, о производительности доступа к списку через indeces VS через перечислитель. Чтобы работать с некоторыми фактами, я написал следующий тест:
static void Main(string[] args)
{
const int count = 10000000;
var stopwatch = new Stopwatch();
var list = new List<int>(count);
var rnd = new Random();
for (int i = 0; i < count; i++)
{
list.Add( rnd.Next());
}
const int repeat = 20;
double indeces = 0;
double forEach = 0;
for (int iteration = 0; iteration < repeat; iteration++)
{
stopwatch.Restart();
long tmp = 0;
for (int i = 0; i < count; i++)
{
tmp += list[i];
}
indeces += stopwatch.Elapsed.TotalSeconds;
stopwatch.Restart();
foreach (var integer in list)
{
tmp += integer;
}
forEach += stopwatch.Elapsed.TotalSeconds;
}
Console.WriteLine(indeces /repeat);
Console.WriteLine(forEach /repeat);
}
Фактически, он просто обращается к элементам.
Как я и ожидал, доступ к индексу был быстрее. Это результаты сборки Release на моей машине:
0.0347//index access
0.0737//enumerating
Однако я решил немного изменить тест:
//the same as before
...
IEnumerable<int> listAsEnumerable = list;
//the same as before
...
foreach (var integer in listAsEnumerable)
{
tmp += integer;
}
...
И теперь вышло следующее:
0.0321//index access
0.1246//enumerating (2x slower!)
Если мы перечисляем один и тот же список через интерфейс, производительность 2 раза медленнее!
Почему это происходит?
this означает "перечисление через интерфейс в 2 раза медленнее, чем перечисление фактического списка".
Моя догадка заключается в том, что среда выполнения использует разные Enumerator
s: список в первом тесте и общий во втором тесте.