Warum gibt es einen Leistungsunterschied zwischen LINQ (c #) und Seq (f #)?

8

Ich habe sehr einfache C # - und F # -Testprogramme erstellt.

%Vor%

c # 71 ms f # 1797 ms

Ich habe eine zweite Version von F # erstellt, die ähnlich funktioniert wie c #

%Vor%

aber das Ergebnis nicht signifikant verändert (1650ms)

Ich verstehe den großen Unterschied in der Geschwindigkeit zwischen den zwei Sprachen nicht.

Die beiden Programme haben einen sehr ähnlichen IL-Code, beide verwenden IEnumerable, außerdem ersetzt F # den Funktionsaufruf durch Operation.

Ich habe c # -Code basierend auf f # IL-Code umgeschrieben.

%Vor%

Der IL-Code von zwei Programmen ist gleich, aber die Geschwindigkeit ist immer noch sehr unterschiedlich. Ich fand den IL-Unterschied dank Foggy Finder

Der langsame Code

%Vor%

Der schnelle Code

%Vor%     
user1665240 06.02.2017, 18:04
quelle

1 Antwort

8

Der Hauptgrund, warum OP einen Leistungsunterschied sieht, ist, weil Seq.init in F # langsam ist. Der Grund dafür ist, dass in jeder Iteration Seq.upto (welche Seq.init verwendet) ein neues Lazy<_> -Objekt zuweist. Sie können dies in Seq Quelle sehen. Wenn Sie eine Low-Overhead-Funktion wie fun n -> n % 2 haben, kostet die Berechnung eines neuen Lazy<_> -Objekts sowie dessen Auswertung (Mutex-Sperre und -Entsperrung) viel Zeit.

Der zweite Grund, warum OP einen Leistungsunterschied sieht, ist, dass Seq in F # im Allgemeinen langsam ist. Dies wird in diesem PR

durch Manofstick behoben

Mit dem PR-Inplace wird F # Seq im Vergleich zu den vorhandenen Alternativen sehr gut funktionieren (einige Details hier )

Mit all dem Gesagten habe ich einige Vergleiche von verschiedenen Möglichkeiten vorbereitet, um die Berechnung durch den Benutzer zu tun (abgesehen von der offensichtlichen total / 2 ).

%Vor%

Der passende C # -Code:

%Vor%

Die Leistungszahlen, die auf meinem Rechner (Intel Core I5) unter .NET 4.6.1 64bit angezeigt werden:

%Vor%

Seq macht das Schlimmste und verbraucht auch Speicher. Wenn sowohl F # als auch C # -Code LINQ verwendet, gibt es keinen wirklichen Unterschied wie erwartet. Nessos ist eine leistungsstarke Datenpipeline für F # (und C #), die wesentlich besser funktioniert.

"Hard-Coding" eine for-Schleife ist noch besser und die schnellste Lösung ist die Verwendung von SSE bis System.Numerics.Vectors . Leider unterstützt System.Numerics.Vectors % nicht, was den Vergleich etwas unfair macht.

Der Unterschied ist also nicht so sehr ein Sprachproblem, sondern ein Bibliotheksproblem.

    
FuleSnabel 06.02.2017, 20:15
quelle

Tags und Links