Ich implementierte einen Algorithmus in Swift Beta und bemerkte, dass die Leistung sehr schlecht war. Nach genauerer Analyse stellte ich fest, dass einer der Engpässe etwas so Einfaches wie das Sortieren von Arrays war. Der relevante Teil ist hier:
let n = 1000000
var x = [Int](repeating: 0, count: n)
for i in 0..
In C++ dauert eine ähnliche Operation **0,06s** auf meinem Computer.
In Python dauert es **0,6s** (keine Tricks, einfach y = sorted(x) für eine Liste ganzer Zahlen).
In Swift dauert es **6s**, wenn ich es mit folgendem Befehl kompiliere:
xcrun swift -O3 -sdk `xcrun --show-sdk-path --sdk macosx`
Und es dauert sogar **88s**, wenn ich es mit folgendem Befehl kompiliere:
xcrun swift -O0 -sdk `xcrun --show-sdk-path --sdk macosx`
Die Zeiten in Xcode mit "Release" und "Debug" Builds sind ähnlich.
Was stimmt hier nicht? Ich könnte einen Leistungsverlust im Vergleich zu C++ verstehen, aber keine zehnfache Verlangsamung im Vergleich zu reinem Python.
------
**Bearbeiten:** weather bemerkte, dass die Änderung von `-O3` zu `-Ofast` macht, dass dieser Code fast so schnell läuft wie die C++-Version! Allerdings ändert `-Ofast` die Semantik der Sprache stark - in meinem Test hat es **die Überprüfungen für Integerüberläufe und Arrayindexüberläufe deaktiviert**. Zum Beispiel führt der folgende Swift-Code mit `-Ofast` ohne Absturz aus und gibt Müll aus:
let n = 10000000
print(n*n*n*n*n)
let x = [Int](repeating: 10, count: n)
print(x[n])
Also `-Ofast` ist nicht das, was wir wollen; der Sinn von Swift ist, dass wir die Sicherheitsnetze haben. Natürlich haben die Sicherheitsnetze Auswirkungen auf die Leistung, aber sie sollten die Programme nicht 100-mal langsamer machen. Denken Sie daran, dass Java bereits auf Arraygrenzen prüft, und in typischen Fällen ist die Verlangsamung um einen Faktor viel weniger als 2. Und bei Clang und GCC haben wir `-ftrapv` zur Überprüfung (signed) ganzzahliger Überläufe, und das ist auch nicht so langsam.
Also die Frage: Wie können wir vernünftige Leistung in Swift erzielen, ohne die Sicherheitsnetze zu verlieren?
------
**Bearbeiten 2:** In Kommentaren bat Ferruccio um Benchmarks, die fair sind in dem Sinne, dass sie nicht auf integrierten Funktionen beruhen (z.B. sort). Ich denke, das folgende Programm ist ein ziemlich gutes Beispiel:
let n = 10000
var x = [Int](repeating: 1, count: n)
for i in 0..
``
Es gibt keine Arithmetik, also müssen wir uns keine Gedanken über Ganzzahlüberläufe machen. Das Einzige, was wir tun, sind einfach viele Array-Referenzen. Und die Ergebnisse sind hier - Swift -O3 verliert fast um den Faktor 500 im Vergleich zu -Ofast:
* C++ -O3: **0,05 s**
* C++ -O0: 0,4 s
* Java: **0,2 s**
* Python mit PyPy: 0,5 s
* Python: **12 s**
* Swift -Ofast: 0,05 s
* Swift -O3: **23 s**
* Swift -O0: 443 s
(Wenn Sie befürchten, dass der Compiler die sinnlosen Schleifen vollständig optimieren könnte, können Sie es z.B. in `x[i] ^= x[j]` ändern und eine Ausgabeanweisung hinzufügen, die `x[0]` ausgibt. Das ändert nichts; die Zeitmessungen werden sehr ähnlich sein.)
Und ja, hier war die Python-Implementierung eine dumme reine Python-Implementierung mit einer Liste von Ganzzahlen und verschachtelten for-Schleifen. Sie sollte **viel** langsamer sein als nicht optimiertes Swift. Hier scheint etwas ernsthaft mit Swift und der Arrayindizierung kaputt zu sein.
------
**Bearbeiten 4:** Diese Probleme (sowie einige andere Leistungsprobleme) scheinen in Xcode 6 Beta 5 behoben worden zu sein.
Beim Sortieren habe ich jetzt folgende Zeitmessungen:
* clang++ -O3: 0,06 s
* swiftc -Ofast: 0,1 s
* swiftc -O: 0,1 s
* swiftc: 4 s
Für verschachtelte Schleifen:
* clang++ -O3: 0,06 s
* swiftc -Ofast: 0,3 s
* swiftc -O: 0,4 s
* swiftc: 540 s
Es scheint keinen Grund mehr zu geben, das unsichere `-Ofast` (auch bekannt als `-Ounchecked`) zu verwenden; einfach `-O` erzeugt gleichwertigen Code.
`` ```