Warum ist mein Python / numpy-Beispiel schneller als die reine C-Implementierung?

7

Ich habe so ziemlich den gleichen Code in Python und C. Python Beispiel:

%Vor%

C Beispiel:

%Vor%

Etwas Seltsames passiert, wenn ich beide Beispiele durchführe:

%Vor%

Es sieht so aus, als wäre python / numpy doppelt so schnell wie C. Gibt es einen Fehler im obigen Experiment? Wie kannst du es erklären?

P.S. Ich habe Ubuntu 12.04, 8G RAM, Core i5 BTW

    
Artem Mezhenin 22.01.2013, 19:57
quelle

3 Antworten

17

Aktivieren Sie zuerst die Optimierung. Zweitens sind Feinheiten wichtig. Ihr C-Code ist definitiv nicht "grundsätzlich gleich".

Hier ist äquivalenter C-Code:

sinary2.c:

%Vor%

sinary.c:

%Vor%

Ergebnisse:

%Vor%

Der Grund, warum das Programm in zwei Teile aufgeteilt werden muss, ist, den Optimierer etwas zu täuschen. Sonst wird es erkennen, dass die ganze Schleife überhaupt keinen Effekt hat und es optimiert. Wenn man Dinge in zwei Dateien schreibt, sieht der Compiler nicht die möglichen Nebenwirkungen von sin_array , wenn er main kompiliert, und muss daher davon ausgehen, dass er tatsächlich einige davon hat und sie wiederholt aufruft.

Ihr ursprüngliches Programm ist aus mehreren Gründen nicht gleichwertig. Eine besteht darin, dass Sie in der C-Version verschachtelte Schleifen haben und in Python nicht. Ein anderes ist, dass Sie mit Array-Werten in der Python-Version und nicht in der C-Version arbeiten. Eine andere Möglichkeit besteht darin, Arrays in der Python-Version und nicht in der C-Version zu erstellen und zu verwerfen. Und schließlich verwenden Sie float in der Python-Version und double in der C-Version.

Das Aufrufen der Funktion sin mit der entsprechenden Anzahl von Malen führt nicht zu einem gleichwertigen Test.

Auch der Optimierer ist eine wirklich große Sache für C. Der Vergleich von C-Code, auf den der Optimierer nicht verwendet wurde, wenn Sie sich über einen Geschwindigkeitsvergleich wundern, ist das Falsche. Natürlich müssen Sie auch achtsam sein. Der C-Optimierer ist sehr ausgefeilt und wenn Sie etwas testen, das wirklich nichts macht, könnte der C-Optimierer diese Tatsache bemerken und einfach gar nichts tun, was zu einem Programm führt, das lächerlich schnell ist.

    
Omnifarious 22.01.2013, 20:14
quelle
2

Weil "numpy" eine dedizierte mathematische Bibliothek ist, die für Geschwindigkeit implementiert ist. C hat Standardfunktionen für sin / cos, die im Allgemeinen für Genauigkeit abgeleitet werden.

Sie vergleichen auch nicht Äpfel mit Äpfeln, wie Sie Double in C verwenden, und float32 (float) in Python. Wenn wir stattdessen den Python-Code ändern, um float64 zu berechnen, erhöht sich die Zeit auf meinem Computer um etwa 2,5 Sekunden, sodass er ungefähr der korrekt optimierten C-Version entspricht.

Wenn der ganze Test gemacht wurde, um etwas komplizierteres zu tun, das mehr Kontrollstrukturen benötigt (if / else, do / while, usw.), dann würden Sie wahrscheinlich noch weniger Unterschiede zwischen C und Python sehen - weil der C-Compiler das kann. t tu wirklich "sin" schneller - außer du implementierst eine bessere "sin" -Funktion.

Neuere Tatsache, dass Ihr Code auf beiden Seiten nicht ganz derselbe ist ...;)

    
Mats Petersson 22.01.2013 20:21
quelle
0

Sie scheinen die gleiche Operation in C 8192 x 10000 mal, aber nur 10000 in python zu machen (ich habe numpy vorher noch nicht benutzt, damit ich den Code missverstehen kann). Warum verwenden Sie ein Array im Python-Fall (wieder bin ich nicht gewohnt, zu numpy, so ist vielleicht die Dereferenzierung implizit). Wenn Sie ein Array verwenden möchten, achten Sie darauf, dass Doubles einen Leistungseinbruch in Bezug auf Caching und optimierte Vektorisierung haben - Sie verwenden unterschiedliche Typen zwischen beiden Implementierungen (float vs double), aber angesichts des Algorithmus halte ich das nicht für wichtig.

Der Hauptgrund für viele anormale Performance-Benchmark-Probleme rund um C vs Pythis, Pythat ... Ist das einfach die C-Implementierung ist oft schlecht.

Ссылка

Wenn Sie bemerken, dass der Typ C schreibt, um ein Array von doubles zu verarbeiten (ohne restric oder const keywords, wo er hätte), baut er mit optimization und zwingt dann den Compiler, SIMD anstelle von AVE zu verwenden. Kurz gesagt, der Compiler verwendet einen ineffizienten Befehlssatz für Doubles und den falschen Registertyp, wenn er Leistung möchte - Sie können sicher sein, dass die Numba und Numpy so viele Schnickschnack wie möglich verwenden und mit sehr effizientem C ausgeliefert werden und C ++ - Bibliotheken, um damit zu beginnen. Kurz gesagt, wenn Sie Geschwindigkeit mit C wollen, müssen Sie darüber nachdenken, Sie müssen vielleicht sogar den Code zerlegen und vielleicht die Optimierung deaktivieren und stattdessen die Compiler-Instrinsik verwenden. Es gibt Ihnen die Werkzeuge, um es zu tun, also erwarten Sie nicht, dass der Compiler die ganze Arbeit für Sie erledigt. Wenn Sie diesen Freiheitsgrad wollen, verwenden Sie Cython, Numba, Numpy, Scipy usw. Sie sind sehr schnell, aber Sie werden nicht in der Lage sein, jedes bisschen Leistung aus dem Rechner herauszuholen - um das mit C, C ++ oder neu zu machen Versionen von FORTRAN.

Hier ist ein sehr guter Artikel über diese Punkte (ich würde SciPy verwenden):

Ссылка

    
cdcdcd 09.03.2017 14:54
quelle

Tags und Links