web-dev-qa-db-fra.com

Une déclaration LINQ est-elle plus rapide qu'une boucle 'foreach'?

J'écris à un gestionnaire de Mesh Rendering et je pense que ce serait une bonne idée de regrouper toutes les mailles utilisant le même shader, puis de les restituer pendant que je suis dans cette passe.

J'utilise actuellement une boucle foreach, mais je me demandais si l'utilisation de LINQ pourrait me permettre d'augmenter les performances.

106
Neil Knight

Pourquoi LINQ devrait-il être plus rapide? Il utilise également des boucles en interne.

La plupart du temps, LINQ sera un peu plus lent car il introduit des frais généraux. N'utilisez pas LINQ si vous vous souciez beaucoup de la performance. Utilisez LINQ parce que vous voulez un code plus court, mieux lisible et maintenable.

191
codymanix

LINQ-to-Objects en général va ajouter des frais généraux marginaux (plusieurs itérateurs, etc.). Il doit encore faire les boucles, et a délégué appelle, et dereferencing supplémentaire pour obtenir les variables capturées, etc. Dans la plupart des codes, ce sera pratiquement indétectable, et plus que fourni par le plus simple à comprendre le code.

Avec d’autres fournisseurs LINQ tels que LINQ-to-SQL, puis, puisque la requête peut filtrer sur le serveur, il devrait être beaucoup meilleur qu’un appartement foreach, mais vous n’auriez probablement pas fait de couverture "select * from foo" _ de toute façon , donc ce n'est pas nécessairement une comparaison équitable.

Re PLINQ; le parallélisme peut réduire le temps écoulé , mais le temps CPU total augmente généralement un peu en raison des frais généraux liés à la gestion des threads, etc.

56
Marc Gravell

Je pense que LINQ est préférable d'utiliser sur une boucle foreach, car cela vous donne un code beaucoup plus propre et facile à comprendre. Mais LINQ est plus lent que foreach. Pour en savoir plus, consultez l'article LINQ vs FOREACH vs FOR Loop Performance.

18
Pranay Rana

LINQ est plus lent maintenant, mais il pourrait devenir plus rapide à un moment donné. La bonne chose à propos de LINQ est que vous n'avez pas à vous soucier de la façon dont cela fonctionne. Si une nouvelle méthode est conçue pour être incroyablement rapide, les employés de Microsoft peuvent l’appliquer sans même vous le dire et votre code serait beaucoup plus rapide.

Plus important encore, LINQ est simplement beaucoup plus facile à lire. Cela devrait être une raison suffisante.

14
Jouke van der Maas

Il faut probablement noter que la boucle for est plus rapide que la foreach. Par conséquent, pour la publication originale, utilisez une boucle for si vous vous inquiétez des performances d'un composant critique tel qu'un moteur de rendu.

Référence: Dans .NET, quelle boucle est la plus rapide, 'pour' ou 'pour-chaque'?

10
peewee_RotA

Vous pourriez obtenir de meilleures performances si vous utilisez LINQ en parallèle pour des cœurs multiples. Voir LINQ parallèle (PLINQ) (MSDN).

9
mcintyre321

C'est en fait une question assez complexe. Linq rend certaines choses très faciles à faire, que si vous les implémentez vous-même, vous pourriez tomber par hasard (par exemple, linq .Except ()). Ceci s’applique particulièrement à PLinq, et en particulier à l’agrégation parallèle telle que mise en œuvre par PLinq.

En général, pour un code identique, linq sera plus lent en raison de la surcharge liée à l'invocation de délégué.

Si, toutefois, vous traitez un grand nombre de données et appliquez des calculs relativement simples aux éléments, vous obtiendrez une augmentation considérable des performances si:

  1. Vous utilisez un tableau pour stocker les données.
  2. Vous utilisez une boucle for pour accéder à chaque élément (par opposition à foreach ou linq).

    • Remarque: lors de l'analyse comparative, souvenez-vous que si vous utilisez le même tableau/la même liste pour deux tests consécutifs, le cache du processeur accélérera le second. *
3
Adam Brown

Cette question m'intéressait et j'ai donc fait un test tout à l'heure. Utilisation de .NET Framework 4.5.2 sur un processeur Intel (R) Core (TM) i3-2328M à 2,20 GHz, 2 200 MHz, 2 coeurs avec 8 Go de RAM exécutant Microsoft Windows 7 Ultimate.

Il semble que LINQ soit plus rapide que pour chaque boucle. Voici les résultats que j'ai obtenus:

Exists = True
Time   = 174
Exists = True
Time   = 149

Il serait intéressant que certains d'entre vous puissent copier et coller ce code dans une application console et le tester également. Avant de tester avec un objet (employé), j'ai essayé le même test avec des entiers. LINQ était aussi plus rapide là-bas.

public class Program
{
    public class Employee
    {
        public int id;
        public string name;
        public string lastname;
        public DateTime dateOfBirth;

        public Employee(int id,string name,string lastname,DateTime dateOfBirth)
        {
            this.id = id;
            this.name = name;
            this.lastname = lastname;
            this.dateOfBirth = dateOfBirth;

        }
    }

    public static void Main() => StartObjTest();

    #region object test

    public static void StartObjTest()
    {
        List<Employee> items = new List<Employee>();

        for (int i = 0; i < 10000000; i++)
        {
            items.Add(new Employee(i,"name" + i,"lastname" + i,DateTime.Today));
        }

        Test3(items, items.Count-100);
        Test4(items, items.Count - 100);

        Console.Read();
    }


    public static void Test3(List<Employee> items, int idToCheck)
    {

        Stopwatch s = new Stopwatch();
        s.Start();

        bool exists = false;
        foreach (var item in items)
        {
            if (item.id == idToCheck)
            {
                exists = true;
                break;
            }
        }

        Console.WriteLine("Exists=" + exists);
        Console.WriteLine("Time=" + s.ElapsedMilliseconds);

    }

    public static void Test4(List<Employee> items, int idToCheck)
    {

        Stopwatch s = new Stopwatch();
        s.Start();

        bool exists = items.Exists(e => e.id == idToCheck);

        Console.WriteLine("Exists=" + exists);
        Console.WriteLine("Time=" + s.ElapsedMilliseconds);

    }

    #endregion


    #region int test
    public static void StartIntTest()
    {
        List<int> items = new List<int>();

        for (int i = 0; i < 10000000; i++)
        {
            items.Add(i);
        }

        Test1(items, -100);
        Test2(items, -100);

        Console.Read();
    }

    public static void Test1(List<int> items,int itemToCheck)
    {

        Stopwatch s = new Stopwatch();
        s.Start();

        bool exists = false;
        foreach (var item in items)
        {
            if (item == itemToCheck)
            {
                exists = true;
                break;
            }
        }

        Console.WriteLine("Exists=" + exists);
        Console.WriteLine("Time=" + s.ElapsedMilliseconds);

    }

    public static void Test2(List<int> items, int itemToCheck)
    {

        Stopwatch s = new Stopwatch();
        s.Start();

        bool exists = items.Contains(itemToCheck);

        Console.WriteLine("Exists=" + exists);
        Console.WriteLine("Time=" + s.ElapsedMilliseconds);

    }

    #endregion

}
2
Theo Kand.