W moim kontroli dlaczego definiowania wielu modułów w jednym zespole jest wolniejszy niż stworzyć nowy zespół z jednego modułu, za pomocą tych fragmentów kodu:
Single-montażowe Scenariusz:
var an = new AssemblyName("Foo");
var ab = AppDomain.CurrentDomain.DefineDynamicAssembly(an, AssemblyBuilderAccess.Run);
for (int i = 0; i < 10000; i++)
{
ab.DefineDynamicModule("Bar" + i.ToString("000"));
}
Scenariusz
Wielu Montaż:
var an = new AssemblyName("Foo");
for (int i = 0; i < 10000; i++)
{
var ab = AppDomain.CurrentDomain.DefineDynamicAssembly(an, AssemblyBuilderAccess.Run);
ab.DefineDynamicModule("Bar");
}
- Znalazłem, że około 20% (50% w wielu przykładach złożeń) razy, kod źródłowy przechodzi przez wszystkie nazwy modułów, aby sprawdzić, czy nie ma konfliktu. Ta część jest zrozumiała i oczekiwana.
- Podczas używania jednego zestawu, kolejne 60% -80% czasu, CLI's
DefineDynamicModule()
jest pod ciśnieniem. Jednak przy użyciu wielu złożeń ta metoda nigdy nie jest wywoływana; zamiast tego inne metody są odpowiedzialne za pozostałe 50%.
Chodźmy głębiej dokumentacji ECMA-335 dla CLI.
II.6 Zespół to zestaw jednego lub więcej plików wdrożonych jako jednostka.
Page 140
Więc teraz zrozumieć, że zespół jest w zasadzie pakiet i moduły są głównymi składnikami. Przy czym powiedział:
II.6 Moduł jest pojedynczy plik zawierający treść wykonywalny w formacie określonym tutaj. Jeśli moduł zawiera manifest, to określa również moduły (w tym siebie), które tworzą zespół. Zgromadzenie zawiera tylko jeden plik manifestu spośród wszystkich jego plików akt.
Page 140
Na podstawie tych informacji, wiemy, że gdy tworzymy zespół, automatycznie dodać jeden moduł do montażu, jak również. Dlatego nigdy nie otrzymujemy trafienia w funkcję CLI o numerze DefineDynamicModule()
, jeśli nadal będziemy tworzyć nowe złożenia. Zamiast tego otrzymujemy hit w metodzie CLI o nazwie GetInMemoryAssemblyModule()
w celu pobrania informacji o Module Manifestów (moduł, który jest tworzony automatycznie).
Tak więc mamy niewielki wzrost wydajności; z jednym zestawem otrzymujemy moduły 10001, ale z wieloma zespołami otrzymujemy w sumie 10000 modułów. Nie za wiele, więc ten dodatkowy moduł nie powinien być głównym powodem tego.
II.6.5 Gdy element jest w obecnym zespole, ale jest częścią modułu innego niż jednego zawierającego manifest, moduł definiowania zostanie ogłoszony w manifeście zespołu pomocą .module dyrektywa zewnętrzna.
Page 146
i
II.6.7 Manifest moduł, od której nie może być tylko jedna za montaż, zawiera .assembly dyrektywy. Aby wyeksportować typ zdefiniowany w dowolnym innym module złożenia, należy wpisać w manifeście złożenia.
Page 146
Dlatego za każdym razem tworzyć nowy moduł, są faktycznie dodanie nowego pliku do archiwum, a następnie modyfikując pierwszy plik z archiwum odwoływać się do nowego modułu. Zasadniczo w kodzie jednoskładnikowym dodajemy 10000 modułów, a następnie edytujemy pierwszy moduł 10000 razy. Nie dotyczy to kodu wielozespołu, w którym edytujemy pierwszy automatycznie wygenerowany moduł, 10000 razy.
To jest napowiedź, którą widzimy. I wzrasta wykładniczo w moim systemie.
(5000 = 1.5s, 10000 = 6s, 20000 = 25s)
z kodem jednak, wąskim gardłem jest SetMethodIL
funkcja CLR niezarządzanego zadzwonił z metody CreateTypeNoLock.CreateTypeNoLock()
i nie mogłem znaleźć nic w jeszcze dokumentacja na ten temat.
Niestety, trudno jest dokonać dekompilacji i zrozumieć CLR.dll, aby zobaczyć, co faktycznie się tam dzieje, a w rezultacie, właśnie zgadujemy na podstawie publicznych informacji opublikowanych przez Microsoft na tym etapie.
Czy możesz udostępnić pewne szczegóły dotyczące środowiska budowy i środowiska .Net? Próbowałem tego na starej wersji (.NET 3.5 release build) i otrzymałem następujące czasy: Czas na jeden zestaw: 03.6230775; Czas na wiele zjazdów: 02.7712719. Znacznie mniejsza różnica niż to, co widzisz. Jednak ** przy pierwszym uruchomieniu ** zauważyłem znacznie większą różnicę - bliżej Ciebie - sugerując coś, co może mieć profilowanie JIT. – dbc