57 Stimmen

Wann man Lambda-Ausdrücke nicht verwenden sollte

Viele Fragen werden auf Stack Overflow beantwortet, wobei die Mitglieder angeben, wie sie diese realen/zeitlichen Probleme mithilfe von Lambda-Ausdrücke .

Verwenden wir sie zu häufig, und berücksichtigen wir die Auswirkungen der Verwendung von Lambda-Ausdrücken auf die Leistung?

Ich fand ein paar Artikel, die die Leistung Auswirkungen von Lambda vs anonyme Delegierte vs erforscht for / foreach Schleifen mit unterschiedlichen Ergebnissen

  1. Anonyme Delegierte vs. Lambda-Ausdrücke vs. Funktionsaufrufe Leistung
  2. Leistung von foreach vs. List.ForEach
  3. .NET/C# Schleifenleistungstest (FOR, FOREACH, LINQ, & Lambda) .
  4. DataTable.Select ist schneller als LINQ

Was sollten die Bewertungskriterien bei der Auswahl der geeigneten Lösung sein? Abgesehen von dem offensichtlichen Grund, dass der Code bei Verwendung von Lambdas prägnanter und lesbarer ist.

2 Stimmen

Ich empfehle Ihnen, www.lambdaexpression.net zu besuchen.

6 Stimmen

@Delashmate-Domain wird jetzt von Spammern übernommen

37voto

Rui Craveiro Punkte 2178

Auch wenn ich mich auf den ersten Punkt konzentrieren werde, möchte ich zunächst meine Meinung zum Thema Leistung äußern. Solange die Unterschiede nicht groß sind oder die Nutzung intensiv ist, kümmere ich mich in der Regel nicht um Mikrosekunden, die in der Summe für den Benutzer keinen sichtbaren Unterschied ausmachen. Ich betone, dass es mir nur dann egal ist, wenn es sich um nicht-intensive aufgerufene Methoden handelt. Wo ich besondere Leistungsüberlegungen anstelle, ist die Art und Weise, wie ich die Anwendung selbst entwerfe. Ich kümmere mich um die Zwischenspeicherung, um die Verwendung von Threads, um clevere Methoden zum Aufrufen von Methoden (ob mehrere Aufrufe oder nur ein Aufruf), ob Verbindungen gepoolt werden sollen oder nicht, usw., usw. In der Tat konzentriere ich mich normalerweise nicht auf die reine Leistung, sondern auf die Skalierbarkeit. Es ist mir egal, ob es für einen einzelnen Benutzer um ein winziges Stückchen einer Nanosekunde besser läuft, aber ich lege großen Wert darauf, dass ich das System mit einer großen Anzahl gleichzeitiger Benutzer belasten kann, ohne dass ich die Auswirkungen bemerke.

Dies vorausgeschickt, möchte ich meine Meinung zu Punkt 1 darlegen. Ich liebe anonyme Methoden. Sie bieten mir große Flexibilität und einen eleganten Code. Ein weiteres großartiges Merkmal anonymer Methoden ist, dass sie es mir ermöglichen, lokale Variablen direkt aus der Containermethode zu verwenden (aus der C#-Perspektive, nicht aus der IL-Perspektive, natürlich). Sie ersparen mir oft eine Menge Code. Wann verwende ich anonyme Methoden? Jedes Mal, wenn das Stück Code, das ich benötige, nicht an anderer Stelle gebraucht wird. Wenn es an zwei verschiedenen Stellen verwendet wird, mag ich Copy-Paste als Wiederverwendungstechnik nicht, also verwende ich einen einfachen alten Delegaten. Wie shoosh schon sagte, ist es nicht gut, Code zu duplizieren. Theoretisch gibt es keine Leistungsunterschiede, da Anonyme C# Tricks sind, nicht IL Zeug.

Das meiste, was ich über anonyme Methoden denke, gilt auch für Lambda-Ausdrücke, da letztere als kompakte Syntax zur Darstellung anonymer Methoden verwendet werden können. Nehmen wir die folgende Methode an:

public static void DoSomethingMethod(string[] names, Func<string, bool> myExpression)
{
    Console.WriteLine("Lambda used to represent an anonymous method");
    foreach (var item in names)
    {
        if (myExpression(item))
            Console.WriteLine("Found {0}", item);
    }
}

Sie erhält ein Array von Strings und ruft für jeden dieser Strings die ihr übergebene Methode auf. Wenn diese Methode "true" zurückgibt, steht dort "Found...". Sie können diese Methode auf folgende Weise aufrufen:

string[] names = {"Alice", "Bob", "Charles"};
DoSomethingMethod(names, delegate(string p) { return p == "Alice"; });

Sie können es aber auch folgendermaßen nennen:

DoSomethingMethod(names, p => p == "Alice");

Es gibt keinen Unterschied in der IL zwischen den beiden, wobei diejenige, die den Lambda-Ausdruck verwendet, viel besser lesbar ist. Auch hier gibt es keine Auswirkungen auf die Leistung, da dies alles C#-Compiler-Tricks sind (keine JIT-Compiler-Tricks). Genauso wenig wie ich das Gefühl hatte, dass wir anonyme Methoden übermäßig verwenden, glaube ich, dass wir Lambda-Ausdrücke zur Darstellung anonymer Methoden übermäßig verwenden. Die gleiche Logik gilt natürlich auch für wiederholten Code: Verwenden Sie keine Lambdas, sondern reguläre Delegierte. Es gibt noch andere Einschränkungen, die Sie zu anonymen Methoden oder einfachen Delegaten zurückführen, wie out oder ref argument passing.

Ein weiterer Vorteil von Lambda-Ausdrücken ist, dass die gleiche Syntax nicht für eine anonyme Methode verwendet werden muss. Lambda-Ausdrücke können auch... Sie ahnen es, Ausdrücke darstellen. Nehmen Sie das folgende Beispiel:

public static void DoSomethingExpression(string[] names, System.Linq.Expressions.Expression<Func<string, bool>> myExpression)
{
    Console.WriteLine("Lambda used to represent an expression");
    BinaryExpression bExpr = myExpression.Body as BinaryExpression;
    if (bExpr == null)
        return;
    Console.WriteLine("It is a binary expression");
    Console.WriteLine("The node type is {0}", bExpr.NodeType.ToString());
    Console.WriteLine("The left side is {0}", bExpr.Left.NodeType.ToString());
    Console.WriteLine("The right side is {0}", bExpr.Right.NodeType.ToString());
    if (bExpr.Right.NodeType == ExpressionType.Constant)
    {
        ConstantExpression right = (ConstantExpression)bExpr.Right;
        Console.WriteLine("The value of the right side is {0}", right.Value.ToString());
    }
 }

Beachten Sie die leicht veränderte Unterschrift. Der zweite Parameter empfängt einen Ausdruck und nicht einen Delegaten. Der Aufruf dieser Methode wäre wie folgt:

DoSomethingExpression(names, p => p == "Alice");

Das ist genau derselbe Aufruf, den wir bei der Erstellung einer anonymen Methode mit einem Lambda gemacht haben. Der Unterschied ist, dass wir hier keine anonyme Methode, sondern einen Ausdrucksbaum erstellen. Dank dieser Ausdrucksbäume können wir dann Lambda-Ausdrücke in SQL übersetzen, was zum Beispiel Linq 2 SQL macht, anstatt für jede Klausel wie Where, Select usw. etwas in der Engine auszuführen. Das Schöne daran ist, dass die Aufrufsyntax dieselbe ist, egal ob man eine anonyme Methode erstellt oder einen Ausdruck sendet.

30voto

Jerry Nixon Punkte 30239

Meine Antwort wird nicht populär sein.

Ich glaube, dass Lambdas aus drei Gründen zu 99 % immer die bessere Wahl sind.

Erstens ist es ABSOLUT nicht falsch, anzunehmen, dass Ihre Entwickler intelligent sind. Andere Antworten gehen von der Annahme aus, dass alle Entwickler außer Ihnen dumm sind. Dem ist nicht so.

Zweitens sind Lamdas (und andere) eine moderne Syntax - und morgen werden sie noch alltäglicher sein, als sie es heute schon sind. Der Code Ihres Projekts sollte sich an aktuellen und neuen Konventionen orientieren.

Drittens mag es für Sie einfacher sein, Code "auf die altmodische Art" zu schreiben, aber für den Compiler ist es nicht einfacher. Das ist wichtig, denn alte Ansätze haben kaum eine Chance, verbessert zu werden, wenn der Compiler überarbeitet wird. Lambdas (u.a.), die sich auf den Compiler verlassen, um sie zu erweitern, können davon profitieren, wenn der Compiler sie im Laufe der Zeit besser handhabt.

Zusammengefasst:

  1. Entwickler können damit umgehen
  2. Jeder tut es
  3. Es gibt ein Zukunftspotenzial

Auch hier weiß ich, dass dies keine beliebte Antwort sein wird. Und glauben Sie mir: "Einfach ist am besten" ist auch mein Mantra. Die Wartung ist ein wichtiger Aspekt bei jeder Quelle. Ich verstehe das. Aber ich denke, wir überschatten die Realität mit einigen klischeehaften Faustregeln.

// Jerry

19voto

shoosh Punkte 73374

Code-Duplizierung.
Wenn Sie dieselbe anonyme Funktion mehr als einmal schreiben, sollte es nicht nur eine sein.

14voto

Marc Gravell Punkte 970173

Nun, wenn wir über die Verwendung von Delegaten sprechen, sollte es keinen Unterschied zwischen Lambda- und anonymen Methoden geben - sie sind dasselbe, nur mit einer anderen Syntax. Und benannte Methoden (die als Delegaten verwendet werden) sind aus Sicht der Laufzeit ebenfalls identisch. Der Unterschied besteht also zwischen der Verwendung von Delegaten und Inline-Code, d.h.

list.ForEach(s=>s.Foo());
// vs.
foreach(var s in list) { s.Foo(); }

(wobei ich erwarten würde, dass Letzteres schneller geht)

Und wenn Sie über etwas anderes sprechen andere als In-Memory-Objekte sind Lambdas eines der mächtigsten Werkzeuge, wenn es darum geht, die Typüberprüfung aufrechtzuerhalten (anstatt die ganze Zeit Strings zu parsen).

Sicherlich gibt es Fälle, in denen eine einfache foreach mit Code wird schneller sein als die LINQ-Version, da es weniger Aufrufe gibt, die eine geringe, aber messbare Zeit kosten. In vielen Fällen ist der Code jedoch einfach nicht der Engpass, und der einfachere Code (insbesondere für die Gruppierung usw.) ist viel mehr wert als ein paar Nanosekunden.

Beachten Sie auch, dass es in .NET 4.0 zusätzlich Expression Knotenpunkte für Dinge wie Schleifen, Kommas, usw. Die Sprache unterstützt sie nicht, aber die Laufzeitumgebung schon. Ich erwähne dies nur der Vollständigkeit halber: Ich sage sicher nicht, dass Sie manuelle Expression Konstruktion, bei der foreach würde genügen!

6voto

Razzie Punkte 30442

Ich würde sagen, dass die Leistungsunterschiede in der Regel so gering sind (und im Falle von Schleifen offensichtlich, wenn man sich die Ergebnisse des zweiten Artikels ansieht (übrigens hat Jon Skeet einen ähnlichen Artikel aquí )), dass Sie sich fast nie allein aus Leistungsgründen für eine Lösung entscheiden sollten, es sei denn, Sie schreiben eine Software, bei der die Leistung absolut entscheidend ist. die die wichtigste nichtfunktionale Anforderung, und man muss wirklich Mikro-Optimierungen vornehmen.

Wann ist was zu wählen? Ich denke, das hängt von der Situation, aber auch von der Person ab. Nur als Beispiel: Manche Leute bevorzugen List.Foreach gegenüber einer normalen foreach-Schleife. I persönlich Ich bevorzuge Letzteres, da es in der Regel besser lesbar ist, aber wer bin ich, dass ich dagegen argumentieren könnte?

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X