Изпълнение на изброяващи стойности спрямо референтен тип

Enumerable.Empty ()
В предишна статия се съсредоточих върху Enumerable.Empty (), тъй като това е най-простата възможна реализация на IEnumerable. Използвах моя собствена версия на кода, която е по-лесна за разбиране, в сравнение с тази, която в момента се намира в LINQ.
Скорошна заявка за сливане в хранилището dotnet / corefx я променя в нещо много близко до моята версия. Разликата е, че те използват сингъл от референтен тип, който реализира IEnumerable и IEnumerator. Това е възможно само защото Empty
Като се има предвид, че преди това всички изброители в BCL бяха типови стойности поради причини за производителност, бях любопитна за тази промяна.
Разглеждайки това, разбрах, че има много възможни реализации на Enumerable.Empty
EmptyStruct
EmptyEnumerableStruct
Той няма метод на Dispose (), така че опита / накрая блок няма да бъде използван от foreach.
Това е тип стойност, така че, когато се използва директно в foreach, няма да се получи бокс и всички обаждания от метода ще бъдат директни (няма виртуални обаждания). Той не може да бъде предаван на IEnumerable
EmptyDisposableStruct и EmptyBoxedDisposableStruct
EmptyEnumerableDisposableStruct
foreach ще използва публичните методи, които връщат типовете изрично (не интерфейси), така че да не се случват бокс или виртуални обаждания. Ако се предава на IEnumerable
EmptyClass
Това е версия, много близка до тази, намираща се в клона „master“ на хранилището „dotnet / corefx“. Той е реализиран тук, тъй като все още не е пуснат.
EmptyEnumerableClass
Той реализира единичен шаблон, така че за всеки използван тип T се създава само един екземпляр от класа. Всички обаждания на метод връщат препратка към този случай.
EmptyYieldBreak
Този метод използва реализацията, която се създава от компилатора, когато се използва ключовата дума за добив. В този случай това води до празно изброяване.
Това е референтен тип, който реализира IEnumerable
LinqEmpty
Това използва версията на Enumerable.Empty
EmptyList и EmptyBoxedList
Използва изброителя, върнат от празен списък
EmptyArray и EmptyBoxedArray
Използва изброителя, върнат от празен масив
Показатели
Създадох бенчмарк с помощта на BenchmarkDotNet, съдържащ всички тези реализации и тук имаме резултатите:

- Това, че опитате / най-накрая блокира, няма никаква разлика.
- EmptyDisposableStruct
, който е тип стойност, е 33 пъти по-бърз от EmptyClass (новата версия на LINQ), но 2 пъти по-бавен, когато се предава на IEnumerable . - Два случая на EmptyDisposableStruct
са поставени в кутията (2 x 24B), когато са предадени на IEnumerable . - EmptyClass (новата версия на LINQ) използва препратки към случаи, разпределени по-рано на купчината, така че да няма разпределения на купчина по време на метода за сравнение.
- LinqEmpty (текущата реализация на LINQ) се основава на EmptyBoxedArray, така че те имат същата производителност.
- EmptyClass (новата версия на LINQ) е с 30% по-бърз от LinqEmpty (текущата реализация на LINQ).
- Най-бавният е EmptyBoxedList ...
заключение
Въпреки че EmptyDisposableStruct е много по-бърз от EmptyClass (новата версия на LINQ), резултатът от Enumerable.Empty
Надявам се да ви е харесало това пътуване толкова, колкото и аз. Това не е само за Enumerable.Empty