break; und continue frage

  • C#
  • .NET (FX) 4.5–4.8

Es gibt 46 Antworten in diesem Thema. Der letzte Beitrag () ist von BiedermannS.

    jvbsl schrieb:

    Du hast die Behauptung aufgestellt, dass LinQ performanter sei

    *sein kann.

    Ich hab nur gesagt dass ich Code habe, der mit Linq besser performt, nicht dass jeder Code mit Linq besser performt.

    jvbsl schrieb:

    Ich denke sonst ist das Ergebnis nicht ganz fair, da wenn ich das richtig gesehen habe der LinQ teil erst in Zeile 92 evaluated wird


    Richtig. Wenn man das Query zu einer Liste forced ist es gleich schnell wie die For Methode. Aber da man im vorhinein nicht immer weiß, wie das Ergebnis einer Methode verwendet wird, ist es in diesem Fall sinnvoller es lazy zu machen, da somit nur das evaluiert wird, was auch benötigt wird. Vor allem wenn einer der Schritte länger dauert.
    Dann hast du nämlich eine Methode die dir potentiell alle Ergebnisse liefert, allerdings auch noch gefiltert werden kann und nur die nötige Arbeit verrichtet.

    z.B.:
    Hier ist es weit sinnvoller Linq zu verwenden als eine for loop, denn die for loop müsste für den jeweiligen Filter angepasst werden, um nicht unnötige Arbeit zu verrichten.

    C#-Quellcode

    1. ​static int SomeSlowOperation(int value)
    2. {
    3. return value * 2; // just pretend something really slow happens here
    4. }
    5. static IEnumerable<int> CalculateAll(IEnumerable<int> values)
    6. {
    7. return from value in values
    8. select SomeSlowOperation(value);
    9. }
    10. static void Main(string[] args)
    11. {
    12. var values = Enumerable.Range(1, 10000);
    13. var results = CalculateAll(values);
    14. foreach(var result in results.TakeWhile(result => result < 100))
    15. {
    16. Console.WriteLine(result);
    17. }
    18. Console.ReadLine();
    19. }
    SWYgeW91IGNhbiByZWFkIHRoaXMsIHlvdSdyZSBhIGdlZWsgOkQ=

    Weil einfach, einfach zu einfach ist! :D

    C#-Quellcode

    1. static IEnumerable<int> CalculateAll(IEnumerable<int> values)
    2. {
    3. foreach(var val in values)
    4. yield return SomeSlowOperation(val);
    5. yield break;
    6. }
    7. [...]
    8. foreach(var result in results)//zusätzlicher Enumerator wird gesaprt
    9. {
    10. if (result >= 100)
    11. break;
    12. Console.WriteLine(result);
    13. }

    Just saying :D
    Und sobald ich dann eine List/Array hab übergeb ich die direkt und schon spar ich mir das Enumerator allokieren, was mit LinQ nicht geht, da LinQ auf IEnumerable arbeitet.

    Und vielleicht ist es falsch rübergekommen, aber ich verdamme LinQ nicht vollständig, mir ging es von Anfang an nur um deine Behauptung(die ich evtl. auch nur falsch verstanden habe):
    Also nocheinmal:
    Für jede LinQ Lösung gibt es eine Äquivalenten Code ohne LinQ der besser oder gleich performt.
    Ich wollte auch mal ne total überflüssige Signatur:
    ---Leer---
    Klar gibt es die und iterator sind auch ein tolles Konzept.
    Aber ich bin mittlerweile ein riesen Fan von Code der Ausdrückt was passieren soll und nicht wie.

    Das größte Problem mit Schleifen und iteratoren ist, dass ich mir die Implementierung ansehen muss um zu verstehen was passiert. Das kostet Zeit und es macht es einfacher einen Bug einzubauen.

    Im Endeffekt muss man sowieso anhand der Problemstellung entscheiden was besser ist, aber grundsätzlich sollte man die höchste Abstraktion die zur Verfügung steht bevorzugen. Wenn man ein Problem mit der Performance hat, erst profilen und danach die Hot-Paths optimieren.

    Wenn ich einen High Performance TCP Server schreibe, dann würd ich auch kein LINQ (und wahrscheinlich auch kein C# ;) ) sonder Loops verwenden, weil man besser optimieren kann.

    Ich glaube wir haben uns da gegenseitig etwas falsch verstanden. :D

    P.S.: Ich werd mir mal den IL code der beiden Methoden durchsehen. Würd mich interessieren zu was die zwei kompiliert werden ^^

    Edit: Was ich vergessen habe zu sagen
    Sobald WebRequests dabei sind ist es von der Performance her ziemlich egal ob man Loops, Iterator oder LINQ verwendet. Keines der Drei wird das Bottleneck sein. Man muss halt bei normalen Loops nur beachten, dass die Abbruch Bedingung direkt in die Loop mit rein muss und nicht wie bei Iteratoren und LINQ einfach im Nachhinein drangehängt werden.
    SWYgeW91IGNhbiByZWFkIHRoaXMsIHlvdSdyZSBhIGdlZWsgOkQ=

    Weil einfach, einfach zu einfach ist! :D

    Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von „BiedermannS“ ()

    Zur leserlichkeit finde ich die Query Schreibeweise von LinQ wesentlich unleserlicher als Schleifen(kann Gewöhnungssache sein). Aber ich bin viel schneller bei normalen Schleifen, oder der Schreibeweise mit den Extension-Methods:

    C#-Quellcode

    1. static IEnumerable<int> CalculateAll(IEnumerable<int> values)
    2. {
    3. return values.Select(SomeSlowOperation);
    4. }

    wobei man das natürlich direkt inlinen könnte :D Aber rein von der Reihenfolge wie es sich liest find ich die Schreibweise viel intuitiver und näher an der menschlichen Sprache.
    Ich wollte auch mal ne total überflüssige Signatur:
    ---Leer---
    Ja ist Gewöhnungssache. Bei kleineren Code Beispielen sind die Extension Methods definitiv schöner :)

    Ich hab grad den IL angesehen und etwas recherchiert.

    Unterschiede zwischen LINQ und Iterator:
    • Iterator werden vom Compiler zu einer Statemachine umgewandelt
    • LINQ verwendet hingegen einen interne IEnumerable Klasse
    • LINQ hat (in diesem Beispiel) eine Allozierung mehr als der Iterator
    • LINQ läuft langsamer als der Iterator
    Anscheinend wird die generierte Statemachine besser optimiert als das generisch gehaltene LINQ. Aber ich finde LINQ dennoch schöner zu schreiben als Iterators. Vor allem wenn mehrere Dinge ineinander verschachtelt sind. (Macht man da Iterators in Iterators?)
    SWYgeW91IGNhbiByZWFkIHRoaXMsIHlvdSdyZSBhIGdlZWsgOkQ=

    Weil einfach, einfach zu einfach ist! :D
    Klar LinQ immer dann wenn es nichts ausmacht und solange es noch gut lesbar bleibt und nicht zu viel wird.

    BiedermannS schrieb:

    Macht man da Iterators in Iterators

    Ich hab keine Ahnung wie du das meinst
    Ich wollte auch mal ne total überflüssige Signatur:
    ---Leer---