2012-02-21 17 views
6

Stavo leggendo questo post qui su micro ORM utilizzato su SO.Che cosa significa cucinare un metodo?

L'autore ha mostrato questo 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 

poi disse:

Nella traccia sopra si può vedere che 'EntityRef' sta cuocendo un metodo, che non è un problema, a meno che non avvenga centinaia di volte al secondo.

Qualcuno potrebbe spiegare la traccia dello stack in relazione a ciò che intendeva per "cottura di un metodo" e perché sarebbe un problema di prestazioni?

risposta

10

Quando fai qualcosa di simile:

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

il compilatore si trasforma in qualcosa di simile:

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

Cioè, il compilatore genera il IL per il metodo. Quando si genera l'oggetto query in fase di esecuzione, l'oggetto restituito da Dove trattiene un delegato al predicato ed esegue il predicato quando necessario.

Ma è possibile creare IL per il delegato in fase di esecuzione se si desidera. Quello che fai è mantenere il corpo del predicato come un albero di espressioni . In fase di esecuzione, l'albero delle espressioni può compilarsi dinamicamente in un IL nuovo di zecca; Fondamentalmente avviamo un compilatore molto semplificato che sa come generare IL per gli alberi di espressione. In questo modo è possibile modificare i dettagli del predicato in fase di esecuzione e ricompilare il predicato senza dover ricompilare l'intero programma.

L'autore di quel commento sta usando "baking" come slang per "generazione di codice leggero dinamico".

+0

Grazie, potresti fornire un esempio o spiegare una circostanza sul motivo per cui l'albero delle espressioni dovrebbe essere ricompilato in fase di runtime? Ad esempio, nel tuo esempio, c'è qualche parte di ciò che ricompilare in fase di runtime? –

+1

@Lolcoder: Supponiamo di aver ottenuto i dettagli della query dall'utente, perché, ad esempio, hanno digitato la parola chiave su cui volevano effettuare la ricerca, o se volevano eseguire un filtro, o un ordine, o qualsiasi altra cosa. –

0

È un modo elegante per dire che stanno emettendo codice dinamico usando Refrection.Emit. Un processo notoriamente lento.

+0

oh, quindi la performance colpita qui sta usando la riflessione? –

+0

@Lolcoder: il risultato della prestazione è l'utilizzo di codice gen leggero e leggero, il cui codice si trova nello spazio dei nomi di Reflection. –

1

Si riferisce alla creazione di un metodo in modo dinamico in fase di esecuzione, ad esempio utilizzando un albero di espressioni. Compilare l'albero delle espressioni in un metodo e restituire un delegato per il metodo compilato potrebbe essere chiamato "cottura" del metodo.

+0

come lo sai dallo stacktrace? solo la prima riga che dice DynamicMethod.CreateDelegate? –

+1

@Lolcoder Non sto dicendo che questa traccia dello stack funzioni specificamente con o su un albero di espressioni. Parlo generalmente della mia comprensione del termine "cuocere un metodo". Potresti farlo emettendo il codice IL; puoi farlo usando un albero delle espressioni; e potrebbero esserci altri modi per farlo. O chiedevi in ​​generale come si fa a sapere che la traccia dello stack indica "cottura"? Questo è evidente dalle chiamate a 'Compile' e' CreateDelegate'. – phoog