2014-04-04 11 views
8

Qualcuno potrebbe spiegare questi risultati? So che ci sono domande duplicati, ma devo ancora trovare una singola domanda che è venuto alla stessa conclusione, come i miei risultati: oLINQ vs foreach vs per i risultati dei test delle prestazioni

using System; 
using System.Collections.Generic; 
using System.Diagnostics; 
using System.Linq; 
using System.Text; 
using System.Threading.Tasks; 

namespace SpeedTest 
{ 
    class Person 
    {  
     public Person(string name) 
     { 
      this.Name = name; 
     } 

     public string Name { get; set; } 
    } 

    class Program 
    { 
     static void Main(string[] args) 
     { 
      var people = new List<Person>(); 
      AddTwins("FRANCISCO", people); 
      var stopwatch = new Stopwatch(); 

      string name = "OCSICNARF"; 

      long linqTime = 0L; 
      long foreachTime = 0L; 
      long forTime = 0L; 

      stopwatch.Start(); 
      Person person0; 
      var result = from person in people 
         where person.Name == name 
         select person; 
      person0 = result.First(); 
      linqTime = stopwatch.ElapsedMilliseconds; 
      stopwatch.Restart(); 
      Person person1; 
      foreach (Person p in people) 
      { 
       if (p.Name == name) 
       { 
        person1 = p; 
        break; 
       } 
      } 
      foreachTime = stopwatch.ElapsedMilliseconds; 
      stopwatch.Restart(); 
      Person person2; 
      for (int i = 0; i < people.Count; i++) 
      { 
       if (people[i].Name == name) 
       { 
        person2 = people[i]; 
        break; 
       } 
      } 
      forTime = stopwatch.ElapsedMilliseconds; 
      stopwatch.Stop(); 

      Console.WriteLine(string.Format("LINQ took {0}ms", linqTime)); 
      Console.WriteLine(string.Format("FOREACH took {0}ms", foreachTime)); 
      Console.WriteLine(string.Format("FOR took {0}ms", forTime)); 
     } 

     static void AddTwins(string name, List<Person> people) 
     { 
      AddTwins(people, name, ""); 
     } 

     private static void AddTwins(List<Person> people, string choices, string chosen) 
     { 
      if (choices.Length == 0) 
      { 
       people.Add(new Person(chosen)); 
      } 
      else 
      { 
       for (int i = 0; i < choices.Length; i++) 
       { 
        // choose 
        char c = choices[i]; 
        string choose1 = choices.Substring(0, i); 
        string choose2 = choices.Substring(i + 1); 
        choices = choose1 + choose2; 

        // explore 
        AddTwins(people, choices, chosen + c); 

        // Unchoose 
        string unchoose1 = choices.Substring(0, i); 
        string unchoose2 = choices.Substring(i); 
        choices = unchoose1 + c + unchoose2; 
       } 
      } 
     } 
    } 
} 

enter image description here

+0

Si prega di consultare http://ericlippert.com/2013/05/14/benchmarking-mistakes-part-one/ –

risposta

16

Non si può mai eseguire la query LINQ, basta creare esso. È necessario utilizzare il metodo ToList o ToArray per forzare un'iterazione, probabilmente non si otterrà un risultato diverso perché LINQ utilizza un ciclo foreach.

Modifica: LINQ richiede un po 'più di tempo perché si sta iterando su tutti gli elementi. Ma nei tuoi altri due loop stai rompendo il loop non appena trovi una corrispondenza. Prova a utilizzare FirstOrDefault anziché Where e dovresti ottenere lo stesso risultato (o simile).

people.FirstOrDefault(p => p.Name == name); 
+0

Il mio male ho appena capito che, vedere i nuovi risultati/codice. –

1

il LINQ sta prendendo tempo perché la query non è mai in realtà valutato.

Linq is lazy per la maggior parte delle operazioni, in realtà non farà nulla finché qualcuno non inizia a enumerare i risultati.

se hai aggiunto

result.Count(); // add this line, query will be evaluated 
linqTime = stopwatch.ElapsedMilliseconds; 
stopwatch.Restart(); 

quindi sono abbastanza sicuro che avresti avuto un non-zero risultato LINQ.

+0

Sì, ho notato, ma voi ragazzi siete stati troppo veloci per me. Guarda i nuovi risultati. Se la query LINQ dovrebbe avere un foreach come il ciclo foreach, perché è più lento? –

+0

se si guarda il codice generato per esso, il foreach è probabilmente piuttosto "piatto", dove il codice generato * probabilmente * ha alcune chiamate di metodo extra per entrare/uscire dal foreach, e restituire cose di ritorno, e cose come quello. –

0

È apparentemente significativo che Sum debba memorizzare un'istanza in scatola dell'enumeratore elenco sull'heap e utilizzare quell'oggetto heap per iterare l'elenco. Sia il foreach inline sia il ciclo for evitano questo; il primo perché il metodo pubblico GetEnumerator di Elenco restituisce un tipo di valore. Se si memorizza un riferimento a persone in una variabile IEnumerable<Person>, il ciclo foreach impiega un po 'più di tempo per raggiungere il risultato.

Inoltre, LINQ deve creare oggetti per l'iteratore dove e il delegato passati ad esso, e lo fa controlli più nulli in modo che possa gettare eccezioni informative se uno degli argomenti è nullo. Ciò potrebbe spiegare il resto del tempo aggiuntivo richiesto per il codice linq.

Problemi correlati