Jak kosztowne jest odbicie .NET?

210

Ciągle słyszę, jak używać złego odbicia. Chociaż generalnie unikam refleksji i rzadko znajduję sytuacje, w których nie można rozwiązać mojego problemu bez niego, zastanawiałem się ...

Czy dla tych, którzy używali refleksji w aplikacjach, zmierzyliście wyniki wydajności i czy naprawdę jest tak źle?

Dan Herbert
źródło
Możesz również sprawdzić to pytanie. stackoverflow.com/questions/224232/…
smaclell
1
Użyj interfejsu API na stronie fastflect.codeplex.com. Przyspieszy odbicie o około 500x dla getters / setters / invokers i niektórych innych rzeczy. Źródło i informacje o tym, jak to działa, są również dostępne, jeśli musisz je rozszerzyć.
Brandon Moore,
3
Jak sprawdzają się te informacje w 2014 roku? Coś się zmieniło w ciągu tych 4 lat?
Arnthor
1
Proste zadanie przypisania wartości do właściwości wystąpienia jest około 150 razy wolniejsze w przypadku odbicia (PropertyInfo.SetValue (wystąpienie, wartość)) niż w przypadku bezpośredniego kodowania (instance.property = wartość). To jest w .NET 4.0
Thanasis Ioannidis

Odpowiedzi:

130

To jest. Ale to zależy od tego, co próbujesz zrobić.

Używam refleksji do dynamicznego ładowania zestawów (wtyczek), a „kara” wydajności nie stanowi problemu, ponieważ operacja jest czymś, co robię podczas uruchamiania aplikacji.

Jeśli jednak odbijasz się w szeregu zagnieżdżonych pętli z wywołaniami odbicia dla każdego, powiedziałbym, że powinieneś ponownie odwiedzić swój kod :)

W przypadku operacji „kilka razy” odbicie jest całkowicie akceptowalne i nie zauważysz żadnych opóźnień ani problemów. Jest to bardzo silny mechanizm i jest nawet używany przez .NET, więc nie rozumiem, dlaczego nie powinieneś spróbować.

Martin Marconcini
źródło
Używałem refleksji, aby uzyskać metodę, nazwę klasy bieżącej metody do zarejestrowania błędu w try-catch. w zasadzie, aby uniknąć zakodowania na stałe nazwy funkcji podczas rejestrowania błędu. Czy muszę się martwić?
Sangram Nandkhile,
@Sramram nie, w porządku
Karthik AMR
@Sangram nie, chyba że masz wiele błędów, które wymagały ciągłego wyłapywania, co powinno być innym problemem :)
Martin Marconcini,
5
@Sangram, podczas gdy wydajność odbicia nie powinna być problemem w twoim przypadku, wygląda na to, że próbujesz zaimplementować to, co zapewniają zwykłe wyjątki w znacznie bardziej elegancki sposób po wyjęciu z pudełka ...
Jacek Gorgoń
152

W swoim wystąpieniu The Performance of Everyday Things Jeff Richter pokazuje, że nazywanie metody metodą refleksji jest około 1000 razy wolniejsze niż normalne.

Wskazówka Jeffa: jeśli musisz wywołać tę metodę wiele razy, użyj refleksji, aby ją znaleźć, następnie przypisz ją do delegata , a następnie wywołaj delegata.

ESRogs
źródło
18
Brałem także udział w Devscovery i zgadzam się z tymi wynikami dla .NET 3.5. Ponowna kompilacja programu testów wydajności Devscovery dla .NET 4 pokazuje ogromną poprawę! Koszt spada do 100 razy wolniej. Użycie refleksji do wyszukiwania typeof () jest niezmienione między .NET 3.5 i .NET 4.
John Wigger
61

Wydajność odbicia będzie zależeć od implementacji (powtarzalne wywołania powinny być buforowane np .:) entity.GetType().GetProperty("PropName"). Ponieważ większość odbić, które widzę na co dzień, jest wykorzystywana do zapełniania jednostek czytnikami danych lub innymi strukturami typu repozytorium, postanowiłem przeprowadzić analizę porównawczą wydajności szczególnie w przypadku odbicia, gdy jest używana do uzyskania lub ustawienia właściwości obiektu.

Opracowałem test, który moim zdaniem jest sprawiedliwy, ponieważ buforuje wszystkie powtarzające się połączenia i tylko razy rzeczywiste wywołanie SetValue lub GetValue. Cały kod źródłowy testu wydajności znajduje się w bitbucket pod adresem : https://bitbucket.org/grenade/accessortest . Kontrola jest mile widziana i zachęcana.

Doszedłem do wniosku, że nie jest to praktyczne i nie zapewnia zauważalnej poprawy wydajności w celu usunięcia odbicia w warstwie dostępu do danych, która zwraca mniej niż 100 000 wierszy w czasie, gdy implementacja odbicia jest wykonana poprawnie.

Wykres czasu (y) względem liczby zaludnionych podmiotów (x)

Powyższy wykres pokazuje wyniki mojego małego testu porównawczego i pokazuje, że mechanizmy, które przewyższają odbicie, robią to zauważalnie dopiero po 100 000 cykli. Większość DAL zwraca tylko kilkaset, a może tysiące wierszy jednocześnie, a na tych poziomach odbicie działa dobrze.

granat
źródło
9
Niekoniecznie. Twoje konwersje DAL mogą dotyczyć tylko kilku tysięcy elementów, ale pomnóż je przez równoczesnych użytkowników korzystających z Twojej aplikacji (jeśli jest to sieć) i może się sumować tak, jakbyś dokonał konwersji milionów elementów. Jeśli dana metoda jest 100 razy wolniejsza, będzie o wiele wolniejsza na małych i dużych zestawach. Wolniej jest wolniej.
Robert Koritnik
@RobertKoritnik Zakłada się, że metody sieciowe na twoim serwerze nie są asynchroniczne
Kurren
Asynchroniczność @kurren nie wpływa na refleksję, ale raczej na zasoby serwera. Asynchroniczne metody sieciowe będą oczywiście w stanie obsłużyć większą liczbę użytkowników, ale refleksja nadal będzie powolna. A refleksja sama w sobie AFAIK jest procesem synchronicznym. Z drugiej strony, pobieranie danych będzie jedyną częścią, która będzie dobrze grała w projektowaniu asynchronicznym.
Robert Koritnik
3
Jaka jest metoda Hyper na wykresie? Czym różni się od Odbłyśnika?
Bryan Legend,
Powinienem był odwołać się do tego @LoneCoder: codeproject.com/Articles/18450/... przez stackoverflow.com/users/23354/marc-gravell
granat
14

Jeśli nie jesteś w pętli, nie martw się o to.

David Plumpton
źródło
12

Moim najbardziej stosownym doświadczeniem było pisanie kodu do porównywania dowolnych dwóch jednostek danych tego samego typu w dużym modelu obiektowym pod względem właściwości. Sprawdziło się, wypróbowało, oczywiście biegło jak pies.

Byłem przygnębiony, a potem zorientowałem się, że bez zmiany logiki mogę użyć tego samego algorytmu do automatycznego generowania metod przeprowadzania porównania, ale statycznego dostępu do właściwości. Dostosowanie kodu do tego celu nie zajęło mi wcale czasu, a ja miałem możliwość dokładnego porównania właściwości encji ze statycznym kodem, który można aktualizować jednym kliknięciem przy każdej zmianie modelu obiektu.

Chodzi mi o to: w rozmowach ze współpracownikami, ponieważ kilkakrotnie zwracałem uwagę, że ich odbiciem może być automatyczne generowanie kodu w celu kompilacji, a nie wykonywanie operacji w czasie wykonywania, i często warto to rozważyć.

Gaz
źródło
Biorąc pod uwagę, że Visual Studio ma tak doskonałą obsługę szablonów, jest to praktyczny sposób na generowanie kodu
Sebastian
12

Nie masowo. Nigdy nie miałem z tym problemu przy tworzeniu pulpitu, chyba że, jak twierdzi Martin, używasz go w głupiej lokalizacji. Słyszałem, że wiele osób ma całkowicie irracjonalne obawy dotyczące jego wydajności w programowaniu komputerów stacjonarnych.

Jednak w Compact Framework (w którym zwykle jestem) jest to raczej anatema i w większości przypadków należy jej unikać jak zarazy. Nadal nie mogę z niego korzystać rzadko, ale muszę bardzo uważać na jego stosowanie, które jest znacznie mniej zabawne. :(

Quibblesome
źródło
5
+1 za nauczenie mnie nowego słowa: klątwa. Również na wzmiankę o irracjonalnych obawach. Boję się programistów, którzy boją się irracjonalnie - to pokazuje, że tak naprawdę nie wiedzą, co robią, i opierają się na tym, co mówią im inni ludzie. kaszel cargo kult kaszel
kichanie
1
Ahhhh Cargo Cult. Teraz jest dobry przykład dziwnego ludzkiego zachowania.
Quibblesome
10

Wystarczająco źle, że musisz się martwić nawet o refleksję wewnętrznie wykonywaną przez biblioteki .NET w celu uzyskania kodu o krytycznym znaczeniu.

Poniższy przykład jest przestarzały - wówczas prawdziwy (2008), ale dawno temu naprawiony w nowszych wersjach CLR. Jednak refleksja jest nadal dość kosztowna!

Przykład: nigdy nie należy używać elementu zadeklarowanego jako „Object” w instrukcji lock (C #) / SyncLock (VB.NET) w kodzie o wysokiej wydajności. Czemu? Ponieważ CLR nie może zablokować typu wartości, co oznacza, że ​​musi wykonać sprawdzenie typu odbicia w czasie wykonywania, aby sprawdzić, czy obiekt jest w rzeczywistości typem wartości, a nie typem odniesienia.

McKenzieG1
źródło
13
uczciwie, sprawdzenie typu odbicia jest szybkie.
Jimmy
1
Do takiego „krytycznego kodu wydajności” powinieneś naprawdę używać .NET na początek?
Seph
1
@Seph: Dynamiczne / refleksyjne części .NET, nr. Ale zwykle C # /. NET, dlaczego nie? Przyspieszenia C ++ w porównaniu z C # są marginalne w warstwie aplikacji (C ++ jest nadal kilka% szybszy w przypadku intensywnych procedur matematycznych). Zgaduję, że nie sugerujesz zebrania ...
DeepSpace101
Typ wartości w ramce (np. Obiekt) można zablokować. @BryceWagner jest poprawny.
Ptactwo
1
Aby być uczciwym (dla mnie), bardziej trafne jest powiedzenie, że odpowiedź jest „przestarzała”, a nie „zwykła bzdura”. Moje uwagi na temat zachowania lock (obj) BYŁY dokładne w momencie ich pisania, ale to specyficzne dla implementacji zachowanie CLR już dawno minęło.
McKenzieG1
5

Podobnie jak w przypadku wszystkich innych elementów programowania, należy zrównoważyć koszty wydajności z uzyskanymi korzyściami. Odbicie jest nieocenionym narzędziem, gdy jest używane ostrożnie. Utworzyłem bibliotekę mapowania O / R w C #, która używała refleksji do tworzenia powiązań. Działa to fantastycznie dobrze. Większość kodu refleksyjnego została wykonana tylko raz, więc każde uderzenie wydajności było dość małe, ale korzyści były świetne. Gdybym pisał nowy algorytm sortowania wymuszonego, prawdopodobnie nie użyłbym refleksji, ponieważ prawdopodobnie skalowałby się słabo.

Doceniam to, że nie odpowiedziałem tutaj dokładnie na twoje pytanie. Chodzi mi o to, że to naprawdę nie ma znaczenia. W razie potrzeby użyj odbicia. To po prostu kolejna funkcja językowa, której musisz nauczyć się, jak i kiedy używać.

Mike Thompson
źródło
3

Odbicie może mieć zauważalny wpływ na wydajność, jeśli użyjesz go do częstego tworzenia obiektów. Opracowałem aplikację opartą na Composite UI Application Block, która w dużym stopniu opiera się na refleksji. Zauważalna była degradacja wydajności związana z tworzeniem obiektów poprzez odbicie.

Jednak w większości przypadków nie ma problemów z użyciem odbicia. Jeśli potrzebujesz tylko sprawdzić jakiś zestaw, polecam Mono.Cecil, który jest bardzo lekki i szybki

aku
źródło
3

Refleksja jest kosztowna ze względu na wiele kontroli, które środowisko wykonawcze musi wykonać za każdym razem, gdy wysyłasz zapytanie o metodę pasującą do listy parametrów. Gdzieś głęboko w środku istnieje kod, który zapętla wszystkie metody dla danego typu, weryfikuje jego widoczność, sprawdza typ zwracany, a także sprawdza typ każdego parametru. Wszystko to kosztuje czas.

Kiedy wykonujesz tę metodę wewnętrznie, pojawia się kod, który wykonuje takie czynności, jak sprawdzanie, że przekazałeś kompatybilną listę parametrów przed wykonaniem rzeczywistej metody docelowej.

Jeśli to możliwe, zawsze zaleca się buforowanie uchwytu metody, jeśli zamierza się go stale używać w przyszłości. Podobnie jak wszystkie dobre wskazówki dotyczące programowania, często warto unikać powtarzania się. W takim przypadku niepotrzebne byłoby ciągłe wyszukiwanie metody z określonymi parametrami, a następnie wykonywanie jej za każdym razem.

Przeszukuj źródło i spójrz na to, co się dzieje.

poseł.
źródło
3

Jak w przypadku wszystkiego, wszystko polega na ocenie sytuacji. W DotNetNuke dostępny jest dość podstawowy komponent, FillObjectktóry wykorzystuje odbicie do wypełniania obiektów z baz danych.

Jest to dość powszechny scenariusz i jest artykuł na temat MSDN, Użycie refleksji do powiązania obiektów biznesowych z kontrolkami formularzy ASP.NET które obejmuje problemy z wydajnością.

Pomijając wydajność, jedną rzeczą, której nie lubię w odbiciu w tym konkretnym scenariuszu, jest to, że ma tendencję do zmniejszania zdolności do zrozumienia kodu na pierwszy rzut oka, co dla mnie nie wydaje się warte wysiłku, jeśli uważasz, że tracisz także kompilację bezpieczeństwo czasu w przeciwieństwie do silnie typowanych zestawów danych lub czegoś takiego jak LINQ to SQL .

lomaxx
źródło
2

Odbicie nie powoduje drastycznego spowolnienia działania aplikacji. Możesz być w stanie zrobić pewne rzeczy szybciej, nie używając odbicia, ale jeśli Odbicie jest najprostszym sposobem na osiągnięcie niektórych funkcji, użyj go. Zawsze możesz refaktoryzować kod od Reflection, jeśli stanie się to problemem.

Chris Pietschmann
źródło
1

Myślę, że przekonasz się, że odpowiedź jest zależna. Nie jest to wielka sprawa, jeśli chcesz umieścić go w aplikacji listy zadań. To wielka sprawa, jeśli chcesz umieścić ją w bibliotece trwałości Facebooka.

Tsimon
źródło