2012-02-21 22 views
6

Czytałem ten post tutaj na micro ORM używane na SO.Co oznacza wypiekanie metody?

Autor pokazał to Stack Trace:

System.Reflection.Emit.DynamicMethod.CreateDelegate 
System.Data.Linq.SqlClient.ObjectReaderCompiler.Compile 
System.Data.Linq.SqlClient.SqlProvider.GetReaderFactory 
System.Data.Linq.SqlClient.SqlProvider.System.Data.Linq.Provider.IProvider.Compile 
System.Data.Linq.CommonDataServices+DeferredSourceFactory`1.ExecuteKeyQuery 
System.Data.Linq.CommonDataServices+DeferredSourceFactory`1.Execute 
System.Linq.Enumerable.SingleOrDefault 
System.Data.Linq.EntityRef`1.get_Entity 

Następnie powiedział:

W ślad powyżej widać, że 'EntityRef' piecze metodę, która nie jest problemem, chyba że dzieje się to 100 razy na sekundę.

Czy ktoś mógłby wytłumaczyć ślad stosu w odniesieniu do tego, co miał na myśli przez "pieczenie metody" i dlaczego byłby to problem z wydajnością?

Odpowiedz

10

Kiedy robisz coś takiego:

int[] items = whatever; 
IEnumerable<int> query = from item in items where item % 2 == 0 select item; 

następnie kompilator zamienia że do czegoś takiego:

static bool Predicate(int item) { return item % 2 == 0; } 
... 
IEnumerable<int> query = Enumerable.Where<int>(items, new Func<int, bool> (Predicate)); 

Oznacza to, że kompilator generuje IL dla metody. Podczas budowania obiektu zapytania w środowisku wykonawczym obiekt zwracany przez funkcję Where wstrzymuje delegata do predykatu i w razie potrzeby wykonuje predykat.

Ale możliwe jest zbudowanie IL dla delegata w czasie wykonywania, jeśli chcesz. Jedyne, co robisz, to utrzymywanie treści predykatu jako drzewa wyrażeń . W czasie wykonywania drzewo wyrażeń może dynamicznie kompilować się do zupełnie nowej IL; w zasadzie uruchamiamy bardzo uproszczony kompilator, który wie, jak wygenerować IL dla drzewek wyrażeń. W ten sposób można zmienić szczegóły predykatu w środowisku wykonawczym i ponownie skompilować predykat bez konieczności ponownej kompilacji całego programu.

Autor tego komentarza używa słowa "pieczenie" jako slangu dla "dynamicznego generowania lekkich kodów".

+0

Dzięki, czy możesz podać przykład lub wyjaśnić okoliczności, dlaczego drzewo wyrażeń musiałoby rekompilować w czasie wykonywania? Na przykład, w twoim przykładzie, czy jest jakaś część tego, która mogłaby być rekompilowana w środowisku wykonawczym? –

+1

@Lolcoder: Załóżmy, że uzyskałeś od użytkownika dane szczegółowe zapytania, ponieważ, powiedzmy, wpisały słowo kluczowe, które chcieli wyszukać, czy chcieli wykonać filtr, zamówienie lub cokolwiek innego.Możesz wtedy zbudować predykat dynamicznie, zamiast kompilatora, który go zbuduje. Innym typowym przypadkiem użycia jest sytuacja, w której drzewo wyrażenia zmienia się w nie jako delegat, ale w dobrej wierze instrukcje SQL, które następnie są przesyłane do bazy danych zaplecza. –

0

To fantazyjny sposób powiedzenia, że ​​emitują kod dynamiczny za pomocą metody Refrection.Emit. Notorycznie powolny proces.

+0

oh, więc wydajność uderzyła tutaj przy użyciu refleksji? –

+0

@Lolcoder: Uderzenie wydajności wykorzystuje dynamiczny lekki gen kodu, którego kod znajduje się w obszarze nazw Reflection. –

1

Odnosi się do tworzenia metody dynamicznie w czasie wykonywania, na przykład za pomocą drzewa wyrażeń. Kompilowanie drzewa wyrażeń do metody i zwracanie delegata dla skompilowanej metody może być nazwane "wypiekiem" metody.

+0

Skąd znasz to ze stosu stacków? tylko pierwsza linia mówi DynamicMethod.CreateDelegate? –

+1

@Lolcoder Nie mówię, że ten ślad stosu konkretnie działa z lub na drzewie wyrażeń. Mówię ogólnie o moim rozumieniu terminu "piec metodę". Możesz to zrobić, wysyłając kod IL; możesz to zrobić za pomocą drzewa wyrażeń; i mogą być na to inne sposoby. A może pytałeś ogólnie, skąd wiadomo, że ślad stosu wskazuje "pieczenie"? Wynika to z połączeń z 'Compile' i' CreateDelegate'. – phoog