Ответ 1
Мой бенчмаркинг не согласуется с вашим бенчмаркингом.
Я провел идентичный тест Алексу и получил противоположный результат. Затем я несколько раз оценил этот показатель и снова наблюдал Cast
быстрее, чем OfType
.
Там не так много, но я считаю, что Cast
имеет край, как и должно, потому что его итератор проще. (Нет is
check.)
Edit: На самом деле после некоторой дополнительной настройки мне удалось получить Cast
на 50 раз быстрее, чем OfType
.
Ниже приведен код теста, который дает самое большое несоответствие, которое я нашел до сих пор:
Stopwatch sw1 = new Stopwatch();
Stopwatch sw2 = new Stopwatch();
var ma = Enumerable.Range(1, 100000).Select(i => i.ToString()).ToArray();
var x = ma.OfType<string>().ToArray();
var y = ma.Cast<string>().ToArray();
for (int i = 0; i < 1000; i++)
{
if (i%2 == 0)
{
sw1.Start();
var arr = ma.OfType<string>().ToArray();
sw1.Stop();
sw2.Start();
var arr2 = ma.Cast<string>().ToArray();
sw2.Stop();
}
else
{
sw2.Start();
var arr2 = ma.Cast<string>().ToArray();
sw2.Stop();
sw1.Start();
var arr = ma.OfType<string>().ToArray();
sw1.Stop();
}
}
Console.WriteLine("OfType: " + sw1.ElapsedMilliseconds.ToString());
Console.WriteLine("Cast: " + sw2.ElapsedMilliseconds.ToString());
Console.ReadLine();
Твики, которые я сделал:
- Выполнять "сгенерировать список строк" один раз, в начале и "кристаллизовать" его.
- Выполните одну из каждой операции перед началом отсчета времени - я не уверен, что это необходимо, но я думаю, что это означает, что JITTER генерирует код заранее, а не время, когда мы синхронизированы?
- Выполнять каждую операцию несколько раз, а не только один раз.
- Измените порядок, если это имеет значение.
На моей машине это приводит к ~ 350 мс для Cast
и ~ 18000мс для OfType
.
Я думаю, что самое большое различие заключается в том, что мы больше не будем считать, сколько времени займет MatchCollection
, чтобы найти следующий матч. (Или, в моем коде, как долго int.ToString()
принимает.) Это резко снижает отношение сигнал/шум.
Изменить: Как указано в шестизначных переменных, причиной такого огромного различия является то, что Cast
будет замыкаться на короткое замыкание и не беспокоить литье отдельных элементов, если оно может отличить целую IEnumerable
. Когда я переключился с использования Regex.Matches
на массив, чтобы избежать измерения времени обработки регулярных выражений, я также переключился на использование чего-то, сместимого на IEnumerable<string>
, и таким образом активировал это короткое замыкание. Когда я изменил свой тест, чтобы отключить это короткое замыкание, я получаю преимущество незначительное для Cast
, а не массивное.