Poniżej krótki, ale kompletny przykładowy programPole dostęp za pośrednictwem tablicy jest wolniejszy dla typów z kilku pól
const long iterations = 1000000000;
T[] array = new T[1 << 20];
for (int i = 0; i < array.Length; i++)
{
array[i] = new T();
}
Stopwatch sw = Stopwatch.StartNew();
for (int i = 0; i < iterations; i++)
{
array[i % array.Length].Value0 = i;
}
Console.WriteLine("{0,-15} {1} {2:n0} iterations/s",
typeof(T).Name, sw.Elapsed, iterations * 1000d/sw.ElapsedMilliseconds);
z T
zastąpiony przez następujące typy
class SimpleClass struct SimpleStruct
{ {
public int Value0; public int Value0;
} }
class ComplexClass struct ComplexStruct
{ {
public int Value0; public int Value0;
public int Value1; public int Value1;
public int Value2; public int Value2;
public int Value3; public int Value3;
public int Value4; public int Value4;
public int Value5; public int Value5;
public int Value6; public int Value6;
public int Value7; public int Value7;
public int Value8; public int Value8;
public int Value9; public int Value9;
public int Value10; public int Value10;
public int Value11; public int Value11;
} }
daje następujące interesujące wyniki na moim komputerze (Windows 7 .NET 4.5 32-bitowy)
SimpleClass 00:00:10.4471717 95,721,260 iterations/s ComplexClass 00:00:37.8199150 26,441,736 iterations/s SimpleStruct 00:00:12.3075100 81,254,571 iterations/s ComplexStruct 00:00:32.6140182 30,661,679 iterations/s
Pytanie 1: Dlaczego numer ComplexClass
jest o wiele wolniejszy niż SimpleClass
? Wydłużony czas wydaje się wzrastać liniowo wraz z liczbą pól w klasie. Zapis na pierwszym polu klasy z dużą ilością pól nie powinien być bardzo różny od zapisu do pierwszego pola klasy z tylko jednym polem, nie?
Pytanie 2: Dlaczego jest ComplexStruct
wolniejsza niż SimpleStruct
? Spojrzenie na kod IL pokazuje, że i
jest zapisywane bezpośrednio do tablicy, a nie do lokalnej instancji ComplexStruct
, która jest następnie kopiowana do tablicy. Tak więc nie powinno być żadnych kosztów ogólnych związanych z kopiowaniem kolejnych pól.
Pytanie dodatkowe: Dlaczego numer ComplexStruct
jest szybszy niż ComplexClass
?
Edit: Zaktualizowane wyniki badań o mniejszej tablicy T[] array = new T[1 << 8];
:
SimpleClass 00:00:13.5091446 74,024,724 iterations/s ComplexClass 00:00:13.2505217 75,471,698 iterations/s SimpleStruct 00:00:14.8397693 67,389,986 iterations/s ComplexStruct 00:00:13.4821834 74,172,971 iterations/s
więc praktycznie żadnej różnicy między SimpleClass
i ComplexClass
, a tylko niewielka różnica między SimpleStruct
i ComplexStruct
. Jednak wydajność znacznie spadła dla SimpleClass
i SimpleStruct
.
Edit: A teraz z T[] array = new T[1 << 16];
:
SimpleClass 00:00:09.7477715 102,595,670 iterations/s ComplexClass 00:00:10.1279081 98,745,927 iterations/s SimpleStruct 00:00:12.1539631 82,284,210 iterations/s ComplexStruct 00:00:10.5914174 94,419,790 iterations/s
Wynik dla 1<<15
jest jak 1<<8
, a wynik dla 1<<17
jest jak 1<<20
.
Jestem zainteresowany, aby usłyszeć kogoś z ostateczną odpowiedzią na wiedzę. Jedna rzecz, która moim zdaniem przyczyni się do spowolnienia złożonych wersji, to zwiększona ilość danych, które muszą zostać przeniesione z pamięci do pamięci podręcznej procesora. – hatchet
Zgadzam się z Carson63000, że różnica między prostymi i złożonymi strukturami jest prawie na pewno spowodowana mniejszą przewagą pamięci podręcznej dla typów złożonych. Jeśli chodzi o klasę struct vs, struct jest typem wartości, podczas gdy klasa jest typem odniesienia, więc istnieje dodatkowy kierunek z klasami. –
Kolejnym interesującym pytaniem jest dlaczego SimpleStruct NIE jest szybszy od SimpleClass? Spodziewałbym się, że będzie najszybszy. – hatchet