2009-10-07 11 views

Répondre

1

Quelques jours avant d'essayer même chose que R & D pour 50000 enregistrements et a constaté que boucle for prend environ 60% de temps que le temps pris par LINQ clause where

temps écoulé pour Linq: 87 ms temps écoulé pour Linq: 48 ms

temps écoulé pour Linq: 143 ms temps écoulé pour Linq: 76 ms

et ainsi de suite .. pour plus de détails voir le code comment je l'ai fait

using System; 
using System.Collections.Generic; 
using System.ComponentModel; 
using System.Data; 
using System.Drawing; 
using System.Linq; 
using System.Text; 
using System.Windows.Forms; 
using System.Diagnostics; 

namespace SearchingList 
{ 
    public partial class Form1 : Form 
    { 
     private int searchingID = 0; 
     public int SearchingID 
     { 
      get 
      {  
       if (string.IsNullOrEmpty(txtID.Text)) 
        searchingID = 0; 
       else 
        int.TryParse(txtID.Text, out searchingID); 
       return searchingID; 
      } 
      set 
      { 
       SearchingID = searchingID; 
      } 
     } 
     public Form1() 
     { 
      InitializeComponent(); 
     } 

     private void btnsearch_Click(object sender, EventArgs e) 
     { 
      List<Customer> lstcustomersFound = new List<Customer>(); 
      Stopwatch stp = new Stopwatch(); 
      stp.Start(); 
      lstcustomersFound = GetSearchedCustomersByLinq(SearchingID, (List<Customer>)dgvAllData.DataSource); 
      stp.Stop(); 
      lblLinq.Text = "Elapsed Time Linq : " + stp.ElapsedMilliseconds.ToString() + " ms"; 
      stp.Start(); 
      lstcustomersFound = GetSearchedCustomersByForLoop(SearchingID, (List<Customer>)dgvAllData.DataSource); 
      stp.Stop(); 
      lblFor.Text ="Elapsed Time for loop : " + stp.ElapsedMilliseconds.ToString() + " ms"; 
      dgvSearched.DataSource = lstcustomersFound; 
     } 

     private List<Customer> GetSearchedCustomersByForLoop(int searchingID, List<Customer> lstcustomers) 
     { 
      List<Customer> lstcustomersFound = new List<Customer>(); 
      foreach (Customer customer in lstcustomers) 
      { 
       if (customer.CusomerID.ToString().Contains(searchingID.ToString())) 
       { 
        lstcustomersFound.Add(customer); 
       } 
      } 
      return lstcustomersFound; 
     } 

     private List<Customer> GetSearchedCustomersByLinq(int searchingID, List<Customer> lstcustomers) 
     { 
      var query = from customer in lstcustomers 
         where customer.CusomerID.ToString().Contains(searchingID.ToString()) 
         select customer as Customer; 
      return query.ToList(); 
     } 


     private void Form1_Load(object sender, EventArgs e) 
     { 
      List<Customer> customers = new List<Customer>(); 
      Customer customer; 
      for (int id = 1; id <= 50000; id++) 
      { 
       customer = new Customer(); 
       customer.CusomerAddress = "Address " + id.ToString(); 
       customer.CusomerID = id; 
       customer.CusomerName = "Cusomer Name " + id.ToString(); 
       customer.CusomerPhone= "Phone " + id.ToString(); 
       customers.Add(customer); 
      } 
      dgvAllData.DataSource = customers; 
     } 

    } 
} 

Classe client

using System; 
using System.Collections.Generic; 
using System.Linq; 
using System.Text; 

namespace SearchingList 
{ 
    public class Customer 
    { 
     public int CusomerID { get; set; } 
     public string CusomerName { get; set; } 
     public string CusomerAddress { get; set; } 
     public string CusomerPhone { get; set; } 
    } 
} 

que la performance est considération que je vais aller au lieu de boucle For Linq

+2

C'est * copier * une liste plutôt que de trouver une entrée spécifique. Je dirais aussi que vous mesurez pour * way * trop peu de temps pour que ces résultats soient significatifs. Votre condition est également très suspecte - la recherche de "10" va trouver "100" par exemple ...et pourquoi convertir le searchID en une chaîne à chaque itération dans la boucle? Je sais que vous faites la même chose dans les deux cas, mais même ainsi je ne l'utiliserais pas comme un bon point de référence. –

+0

Il me manque probablement quelque chose, mais vous ne devez pas réinitialiser ce chronomètre quelque part? – Svish

+0

Je voudrais aussi dire que je suis d'accord avec Jon Skeet ... – Svish

5

Une boucle for peut très bien être très légèrement plus rapidement. Mesurez-le pour en être sûr ... mais regardez la lisibilité. (EDIT: Lorsque vous le mesurez, essayez de le faire pendant plus longtemps que le benchmark dans la réponse acceptée, comparez également le temps pris pour ce morceau de code avec le temps pour le reste de votre programme.) Est-ce vraiment un goulot d'étranglement?

Je n'utiliserais généralement pas de "select", sauf si vous avez réellement besoin de projeter une séquence de résultats. Pour trouver un seul élément, utilisez:

list.Find(x => x.Name == "Foo"); 

ou

list.FirstOrDefault(x => x.Name == "Foo"); 

je crois que les deux sont beaucoup plus lisible que la boucle for correspondante. Si vous cherchez simplement un objet alors vous pourriez envisager d'utiliser un HashSet<T> à la place ou en combinaison avec la liste.

EDIT: Voici un point de référence pour le tester. Le code est en dessous des résultats.

c:\Users\Jon\Test>test 1000000 500000 1000 
FindCustomerLinq: 28531 
FindCustomerListFind: 12315 
FindCustomerForLoop: 9737 
FindCustomerForEachLoop: 14743 

Alors que cherche dans une liste de millions éléments, trouver un à mi-chemin, mais le faire fois. Alors oui, la boucle for est en fait trois fois plus rapide ... mais vous devrez faire un horrible beaucoup beaucoup avant que cette différence réelle devienne significative. Si vous faites ce genre de chose, vous devriez chercher d'autres options comme Dictionary.

using System; 
using System.Collections.Generic; 
using System.Diagnostics; 
using System.Linq; 

public class Customer 
{ 
    public int ID { get; set; } 
    public string Name { get; set; } 
    public string Address { get; set; } 
    public string Phone { get; set; } 
} 

class Test 
{ 
    static void Main(string[] args) 
    { 
     int size = int.Parse(args[0]); 
     int id = int.Parse(args[1]); 
     int iterations = int.Parse(args[2]); 

     var list = new List<Customer>(size); 
     for (int i=0; i < size; i++) 
     { 
      list.Add(new Customer { 
       ID = i, 
       Address = "Address " + i, 
       Name = "Cusomer Name " + i, 
       Phone= "Phone " + i, 
      }); 
     } 

     Time(FindCustomerLinq, list, id, iterations); 
     Time(FindCustomerListFind, list, id, iterations); 
     Time(FindCustomerForLoop, list, id, iterations); 
     Time(FindCustomerForEachLoop, list, id, iterations); 
    } 

    static void Time(Func<List<Customer>, int, Customer> action, 
        List<Customer> list, 
        int id, int iterations) 
    { 
     Stopwatch sw = Stopwatch.StartNew(); 
     for (int i=0; i < iterations; i++) 
     { 
      action(list, id); 
     } 
     sw.Stop(); 
     Console.WriteLine("{0}: {1}", action.Method.Name, (int) sw.ElapsedMilliseconds); 
    } 

    static Customer FindCustomerLinq(List<Customer> customers, int id) 
    { 
     return customers.FirstOrDefault(c => c.ID == id); 
    } 

    static Customer FindCustomerListFind(List<Customer> customers, int id) 
    { 
     return customers.Find(c => c.ID == id); 
    } 

    static Customer FindCustomerForLoop(List<Customer> customers, int id)   
    { 
     for (int i=0; i < customers.Count; i++) 
     { 
      if (customers[i].ID == id) 
      { 
       return customers[i]; 
      } 
     } 
     return null; 
    } 

    static Customer FindCustomerForEachLoop(List<Customer> customers, int id) 
    { 
     foreach (Customer c in customers) 
     { 
      if (c.ID == id) 
      { 
       return c; 
      } 
     } 
     return null; 
    } 
} 
Questions connexes