L’ordine dei metodi di estensione LINQ non influisce sulle prestazioni?

Sono sorpreso che a quanto pare non importa se io aggiungo o aggiungo i metodi di estensione LINQ.

Testato con Enumerable.FirstOrDefault :

  1. hugeList.Where(x => x.Text.Contains("10000")).FirstOrDefault();
  2. hugeList.FirstOrDefault(x => x.Text.Contains("10000"));

     var hugeList = Enumerable.Range(1, 50000000) .Select(i => new { ID = i, Text = "Item" + i }); var sw1 = new System.Diagnostics.Stopwatch(); var sw2 = new System.Diagnostics.Stopwatch(); sw1.Start(); for(int i=0;i x.Text.Contains("10000")).FirstOrDefault(); sw1.Stop(); sw2.Start(); for(int i=0;i x.Text.Contains("10000")); sw2.Stop(); var result1 = String.Format("FirstOrDefault after: {0} FirstOrDefault before: {1}", sw1.Elapsed, sw2.Elapsed); //result1: FirstOrDefault after: 00:00:03.3169683 FirstOrDefault before: 00:00:03.0463219 sw2.Restart(); for (int i = 0; i  x.Text.Contains("10000")); sw2.Stop(); sw1.Restart(); for (int i = 0; i  x.Text.Contains("10000")).FirstOrDefault(); sw1.Stop(); var result2 = String.Format("FirstOrDefault before: {0} FirstOrDefault after: {1}", sw2.Elapsed, sw1.Elapsed); //result2: FirstOrDefault before: 00:00:03.6833079 FirstOrDefault after: 00:00:03.1675611 //average after:3.2422647 before: 3.3648149 (all seconds) 

Avrei immaginato che sarebbe stato più lento anteporre Where dal momento che deve trovare tutti gli elementi corrispondenti e quindi prendere il primo e un FirstOrDefault preceduto, potrebbe produrre il primo elemento trovato.

Q: Qualcuno può spiegare perché sono sulla strada sbagliata?

Avrei immaginato che sarebbe stato più lento anteporre Dove, dal momento che deve trovare tutti gli elementi corrispondenti e quindi prendere il primo e un PrimoOrDefault preceduto, potrebbe produrre il primo elemento trovato. Qualcuno può spiegare perché sono sulla strada sbagliata?

Sei sulla strada sbagliata perché la tua prima affermazione è semplicemente sbagliata. Where non è necessario trovare tutti gli elementi corrispondenti prima di recuperare il primo elemento corrispondente. Where recupera gli oggetti “su richiesta”; se chiedi solo il primo, recupera solo il primo. Se chiedi solo i primi due, recupera solo i primi due.

Jon Skeet fa un bel po ‘sul palco. Immagina di avere tre persone. La prima persona ha un mazzo di carte mescolato. La seconda persona ha una maglietta che dice “dove la carta è rossa”. La terza persona colpisce la seconda persona e dice “dammi la prima carta”. La seconda persona colpisce la prima persona più e più volte finché la prima persona non consegna un cartellino rosso, che la seconda persona consegna alla terza persona. La seconda persona non ha motivo di continuare a picchiare la prima persona; il compito è finito!

Ora, se la t-shirt della seconda persona dice “ordine per grado in ordine crescente”, allora abbiamo una situazione molto diversa. Ora la seconda persona ha davvero bisogno di prendere ogni carta dalla prima persona, al fine di trovare la carta più bassa nel mazzo, prima di consegnare la prima carta alla terza persona.

Questo dovrebbe ora darti l’intuizione necessaria per dire quando l’ordine è importante per motivi di prestazioni. Il risultato netto di “dammi i cartellini rossi e poi ordinali” è esattamente lo stesso di “ordina tutte le carte, poi dammi quelle rosse”, ma il primo è molto più veloce perché non devi passare il tempo a selezionare carte nere che stai per scartare.

Il metodo Where() utilizza l’esecuzione posticipata e fornirà l’elemento corrispondente successivo come richiesto . Ovvero, Where() non valuta e restituisce immediatamente una sequenza di tutti gli oggetti candidati, li fornisce uno alla volta mentre vengono ripetuti.

Poiché FirstOrDefault() interrompe dopo il primo elemento, questo causerà anche a Where() di interrompere l’iterazione.

Pensa a FirstOrDefault() come l’interruzione dell’esecuzione di Where() come se eseguisse break . Ovviamente non è così semplice, ma in pratica poiché FirstOrDefault() interrompe l’iterazione una volta trovato un object, Where() non ha bisogno di procedere oltre.

Ovviamente, questo è nel caso semplice dell’applicazione di FirstOrDefault() su una clausola Where() , se si hanno altre clausole in cui implica la necessità di considerare tutti gli elementi, questo potrebbe avere un effetto, ma questo sarebbe vero sia in usando Where().FirstOrDefault()' combo or just FirstOrDefault ()’ con un predicato.