Swift Beta performance: tri des matrices

j'implémentais un algorithme dans la version bêta de Swift et j'ai remarqué que les performances étaient très mauvaises. Après avoir creusé plus profondément, j'ai réalisé que l'un des goulots d'étranglement était quelque chose d'aussi simple que le tri des matrices. La partie pertinente est ici:

let n = 1000000
var x =  [Int](repeating: 0, count: n)
for i in 0..<n {
    x[i] = random()
}
// start clock here
let y = sort(x)
// stop clock here

en C++, une opération similaire prend 0,06 s sur mon ordinateur.

en Python il faut 0.6 s (pas de trucs, juste y = triés (x) pour une liste de entier.)

dans Swift il faut 6s si je le compile avec la commande suivante:

xcrun swift -O3 -sdk `xcrun --show-sdk-path --sdk macosx`

et il prend autant que 88s si je le compile avec la commande suivante:

xcrun swift -O0 -sdk `xcrun --show-sdk-path --sdk macosx`

Timings dans Xcode avec "Libération" et "Debug" versions sont similaires.

Qu'est-ce qui ne va pas ici? Je pourrais comprendre une certaine perte de performance en comparaison avec C++, mais pas un ralentissement de 10 fois par rapport au Python pur.


Edit: mweathers a remarqué que le fait de changer -O3 en -Ofast fait tourner ce code presque aussi vite que la version C++! Cependant, -Ofast change beaucoup la sémantique de la langue - dans mon test, il désactivé les vérifications pour les dépassements de nombre entier et les dépassements d'indexation de tableau . Par exemple, avec -Ofast le suivre le code Swift s'exécute silencieusement sans s'écraser (et imprime quelques déchets):

let n = 10000000
print(n*n*n*n*n)
let x =  [Int](repeating: 10, count: n)
print(x[n])

donc -Ofast n'est pas ce que nous voulons; le point entier de Swift est que nous avons les filets de sécurité en place. Bien sûr, les filets de sécurité ont un certain impact sur le rendement, mais ils ne devraient pas ralentir les programmes 100 fois. Rappelez-vous que Java vérifie déjà les limites des tableaux, et dans les cas typiques le ralentissement est d'un facteur beaucoup moins que 2. Et à Clang et GCC nous avons a obtenu -ftrapv pour le contrôle (signé) des débordements d'entiers, et il n'est pas lent, soit.

D'où la question: Comment obtenir une performance raisonnable dans Swift sans perdre les filets de sécurité?


Edit 2: j'ai fait plus de benchmarking, avec des boucles très simples le long des lignes de

for i in 0..<n {
    x[i] = x[i] ^ 12345678
}

(Ici l'opération xor est là juste pour que je puisse plus facilement trouver les boucle dans le code assembleur. J'ai essayé de choisir une opération qui est facile à repérer mais aussi "inoffensive" dans le sens où il ne devrait pas exiger de contrôles liés à des débordements d'entiers.)

encore une fois, il y avait une énorme différence dans la performance entre -O3 et -Ofast . J'ai donc regardé le code de l'Assemblée:

  • avec -Ofast j'obtiens à peu près ce à quoi je m'attendais. La partie pertinente est un boucle avec 5 instructions de langage machine.

  • Avec -O3 j'ai quelque chose qui était au-delà de mon imagination la plus folle. La boucle intérieure s'étend sur 88 lignes de code de montage. Je n'ai pas essayé de comprendre tout cela, mais les parties les plus suspectes sont 13 invocations de "callq _swift_retain" et 13 autres invocations de "callq _swift_release". C'est-à-dire, 26 appels de sous-Programmes dans la boucle intérieure !


Edit 3: dans les commentaires, Ferruccio a demandé des benchmarks qui sont justes dans le sens où ils ne reposent pas sur des fonctions intégrées (par exemple tri). Je pense que le programme suivant est un assez bon exemple:

let n = 10000
var x = [Int](repeating: 1, count: n)
for i in 0..<n {
    for j in 0..<n {
        x[i] = x[j]
    }
}

il n'y a pas d'arithmétique, donc nous n'avons pas besoin de nous inquiéter des débordements d'entier. La seule chose que nous faisons est juste beaucoup de références de tableau. Et les résultats sont ici-Swift-O3 perd par facteur presque 500 en comparaison avec-Ofast:

  • C++ - O3: 0,05 s
  • C++ - O0: 0.4 s
  • Java: 0.2 s
  • Python avec PyPy: 0.5 s
  • Python: 12 s
  • Swift-Ofast: 0.05 s
  • Swift-O3: 23 s
  • Swift-O0: 443 s

(si vous craignez que le compilateur n'optimise entièrement les boucles inutiles, vous pouvez le changer en par exemple x[i] ^= x[j] , et ajouter une instruction d'impression qui affiche x[0] . Cela ne change rien; le timing sera très similaire.)

et oui, ici L'implémentation Python était une implémentation pure Python stupide avec une liste d'ints et imbriquée pour des boucles. Il devrait être beaucoup plus lent que Swift non optimisé. Quelque chose semble être sérieusement cassé avec Swift et l'indexation des tableaux.


Edit 4: ces problèmes (ainsi que d'autres problèmes de performance) semblent avoir été corrigés dans Xcode 6 beta 5.

pour le tri, j'ai maintenant les minuteries suivantes:

  • clang++ - O3: 0.06 s
  • swiftc-Ofast: 0.1 s
  • swiftc - O: 0.1 s
  • swiftc: 4 s

pour boucles emboîtées:

  • clang++ - O3: 0.06 s
  • swiftc-Ofast: 0.3 s
  • swiftc - O: 0.4 s
  • swiftc: 540 s

il semble qu'il n'y ait plus de raison d'utiliser le -Ofast (A. K. A. -Ounchecked ); Uni -O produit un code tout aussi bon.

851
demandé sur Cœur 2014-06-08 03:53:45
la source

8 ответов

tl;Dr Swift 1.0 est maintenant aussi rapide que C par ce benchmark en utilisant le niveau d'optimisation de publication par défaut [-O].


voici un quicksort in Swift Beta:

func quicksort_swift(inout a:CInt[], start:Int, end:Int) {
    if (end - start < 2){
        return
    }
    var p = a[start + (end - start)/2]
    var l = start
    var r = end - 1
    while (l <= r){
        if (a[l] < p){
            l += 1
            continue
        }
        if (a[r] > p){
            r -= 1
            continue
        }
        var t = a[l]
        a[l] = a[r]
        a[r] = t
        l += 1
        r -= 1
    }
    quicksort_swift(&a, start, r + 1)
    quicksort_swift(&a, r + 1, end)
}

et le même en C:

void quicksort_c(int *a, int n) {
    if (n < 2)
        return;
    int p = a[n / 2];
    int *l = a;
    int *r = a + n - 1;
    while (l <= r) {
        if (*l < p) {
            l++;
            continue;
        }
        if (*r > p) {
            r--;
            continue;
        }
        int t = *l;
        *l++ = *r;
        *r-- = t;
    }
    quicksort_c(a, r - a + 1);
    quicksort_c(l, a + n - l);
}

les deux travaux:

var a_swift:CInt[] = [0,5,2,8,1234,-1,2]
var a_c:CInt[] = [0,5,2,8,1234,-1,2]

quicksort_swift(&a_swift, 0, a_swift.count)
quicksort_c(&a_c, CInt(a_c.count))

// [-1, 0, 2, 2, 5, 8, 1234]
// [-1, 0, 2, 2, 5, 8, 1234]

tous les deux sont appelés dans le même programme tel qu'écrit.

var x_swift = CInt[](count: n, repeatedValue: 0)
var x_c = CInt[](count: n, repeatedValue: 0)
for var i = 0; i < n; ++i {
    x_swift[i] = CInt(random())
    x_c[i] = CInt(random())
}

let swift_start:UInt64 = mach_absolute_time();
quicksort_swift(&x_swift, 0, x_swift.count)
let swift_stop:UInt64 = mach_absolute_time();

let c_start:UInt64 = mach_absolute_time();
quicksort_c(&x_c, CInt(x_c.count))
let c_stop:UInt64 = mach_absolute_time();

la durée absolue de secondes:

static const uint64_t NANOS_PER_USEC = 1000ULL;
static const uint64_t NANOS_PER_MSEC = 1000ULL * NANOS_PER_USEC;
static const uint64_t NANOS_PER_SEC = 1000ULL * NANOS_PER_MSEC;

mach_timebase_info_data_t timebase_info;

uint64_t abs_to_nanos(uint64_t abs) {
    if ( timebase_info.denom == 0 ) {
        (void)mach_timebase_info(&timebase_info);
    }
    return abs * timebase_info.numer  / timebase_info.denom;
}

double abs_to_seconds(uint64_t abs) {
    return abs_to_nanos(abs) / (double)NANOS_PER_SEC;
}

voici un résumé des niveaux d'optimisation du compilateur:

[-Onone] no optimizations, the default for debug.
[-O]     perform optimizations, the default for release.
[-Ofast] perform optimizations and disable runtime overflow checks and runtime type checks.

Temps en secondes avec [Individualisé] pour n=10_000 :

Swift:            0.895296452
C:                0.001223848

Voici L'option builtin sort () de Swift pour n=10_000 :

Swift_builtin:    0.77865783

Voici [- O] pour n=10_000 :

Swift:            0.045478346
C:                0.000784666
Swift_builtin:    0.032513488

comme vous pouvez le voir, la performance de Swift améliorée par un facteur de 20.

selon réponse de mweathers , le réglage [- Ofast] fait la différence réelle, résultant dans ces temps pour n=10_000 :

Swift:            0.000706745
C:                0.000742374
Swift_builtin:    0.000603576

et pour n=1_000_000 :

Swift:            0.107111846
C:                0.114957179
Swift_sort:       0.092688548

pour comparaison, c'est avec [- Onone] pour n=1_000_000 :

Swift:            142.659763258
C:                0.162065333
Swift_sort:       114.095478272

donc Swift sans optimisations était presque 1000x plus lent que C dans ce benchmark, à ce stade de son développement. D'un autre côté, avec les deux compilateurs réglés à [-Ofast] Swift effectivement effectué au moins aussi bien, sinon légèrement mieux que C.

Il a été souligné que [-Ofast] la sémantique de la le langage, ce qui le rend potentiellement dangereux. C'est ce que dit Apple dans les notes de version de Xcode 5.0:

un nouveau niveau d'optimisation, disponible en LLVM, permet des optimisations agressives. - L'Ofast assouplit certaines restrictions conservatrices, surtout pour les opérations à virgule flottante, qui sont sûres pour la plupart des codes. Il peut produire des gains significatifs de haute performance du compilateur.

ils sont tous d'accord. Si c'est sage ou pas, Je ne pourrais pas dire, mais de ce que je peux dire, il semble raisonnable d'utiliser [- Ofast] dans une version si vous ne faites pas de haute précision arithmétique flottante et vous êtes sûr qu'aucun nombre entier ou tableau débordements sont possibles dans votre programme. Si vous avez besoin de haute performance et contrôles de débordement / arithmétique précise puis choisir une autre langue pour le moment.

BETA 3 MISE À JOUR:

n=10_000 avec [- O] :

Swift:            0.019697268
C:                0.000718064
Swift_sort:       0.002094721

Swift en général est un peu plus rapide et il semble que le tri intégré de Swift ait changé de manière significative.

MISE À JOUR FINALE:

[Individualisé] :

Swift:   0.678056695
C:       0.000973914

[- O] :

Swift:   0.001158492
C:       0.001192406

[- Onchecked] :

Swift:   0.000827764
C:       0.001078914
419
répondu Joseph Mark 2018-09-25 12:36:39
la source

TL;DR : Oui, la seule implémentation du langage Swift est lente, en ce moment . Si vous avez besoin de code rapide, numérique (et d'autres types de code, probablement), il suffit d'aller avec un autre. Dans l'avenir, vous devez réévaluer votre choix. Il pourrait être assez bon pour la plupart du code d'application qui est écrit à un niveau plus élevé, cependant.

D'après ce que je vois dans SIL et LLVM IR, il semble qu'ils ont besoin d'un tas de optimisations pour supprimer les retenues et les rejets, qui pourraient être mis en œuvre dans Clang (pour objectif-C), mais ils n'ont pas encore porté. C'est la théorie que je vais suivre (pour le moment... j'ai encore besoin de confirmer que Clang fait quelque chose à ce sujet), car un profiler exécuter sur le dernier test-case de cette question donne ce "joli" résultat:

Time profiling on -O3 Time profiling on -Ofast

comme l'ont dit plusieurs d'autres, -Ofast est totalement dangereux et change la sémantique du langage. Pour moi, c'est à l'étape" si tu vas utiliser ça, utilise juste une autre langue". Je réévaluerai ce choix plus tard, s'il change.

-O3 nous donne un tas d'appels swift_retain et swift_release qui, honnêtement, ne semblent pas comme ils devraient être là pour cet exemple. L'optimiseur devrait avoir éliminé (la plupart) eux AFAICT, puisqu'il connaît la plupart des informations sur le tableau, et sait qu'il y est (au moins) fortement fait référence.

il ne devrait pas émettre plus de conserve quand il n'est même pas appeler les fonctions qui pourraient libérer les objets. Je ne pense pas qu'un constructeur de tableau puisse retourner un tableau qui est plus petit que ce qui a été demandé, ce qui signifie que beaucoup de contrôles qui ont été émis sont inutiles. Il sait aussi que l'entier ne sera jamais au-dessus de 10k, donc les contrôles de débordement peut être optimisé (pas à cause de -Ofast bizarrerie, mais à cause de la sémantique du langage (rien d'autre ne change que var ni peut y accéder, et ajouter jusqu'à 10k est sûr pour le type Int ).

le compilateur pourrait ne pas être en mesure de déboxifier le tableau ou les éléments du tableau, bien que, puisqu'ils sont passés à sort() , qui est une fonction externe et doit obtenir les arguments qu'il attend. Cela nous obligera à utiliser les valeurs Int indirectement, ce qui le ferait aller un peu plus lent. Cela pourrait changer si la fonction générique sort() (pas de la manière multi-méthode) était disponible pour le compilateur et était mise en ligne.

il s'agit d'une très nouvelle langue (publique), et elle traverse ce que je suppose être beaucoup de changements, car il y a des gens (lourdement) impliqués dans le langage Swift demandant des commentaires et ils disent tous que le langage n'est pas terminé et va changer.

Code utilisé:

import Cocoa

let swift_start = NSDate.timeIntervalSinceReferenceDate();
let n: Int = 10000
let x = Int[](count: n, repeatedValue: 1)
for i in 0..n {
    for j in 0..n {
        let tmp: Int = x[j]
        x[i] = tmp
    }
}
let y: Int[] = sort(x)
let swift_stop = NSDate.timeIntervalSinceReferenceDate();

println("\(swift_stop - swift_start)s")

P. S: Je ne suis pas un expert sur L'Objectif-C ni sur toutes les installations de Cocoa , L'Objectif-C, ou les runtimes Swift. Je suppose aussi des choses que je n'ai pas écrites.

100
répondu filcab 2014-06-23 01:55:11
la source

j'ai décidé de jeter un oeil à cela pour le plaisir, et voici les horaires que j'obtiens:

Swift 4.0.2           :   0.83s (0.74s with `-Ounchecked`)
C++ (Apple LLVM 8.0.0):   0.74s

Swift

// Swift 4.0 code
import Foundation

func doTest() -> Void {
    let arraySize = 10000000
    var randomNumbers = [UInt32]()

    for _ in 0..<arraySize {
        randomNumbers.append(arc4random_uniform(UInt32(arraySize)))
    }

    let start = Date()
    randomNumbers.sort()
    let end = Date()

    print(randomNumbers[0])
    print("Elapsed time: \(end.timeIntervalSince(start))")
}

doTest()

Résultats:

Swift 1.1

xcrun swiftc --version
Swift version 1.1 (swift-600.0.54.20)
Target: x86_64-apple-darwin14.0.0

xcrun swiftc -O SwiftSort.swift
./SwiftSort     
Elapsed time: 1.02204304933548

Swift 1.2

xcrun swiftc --version
Apple Swift version 1.2 (swiftlang-602.0.49.6 clang-602.0.49)
Target: x86_64-apple-darwin14.3.0

xcrun -sdk macosx swiftc -O SwiftSort.swift
./SwiftSort     
Elapsed time: 0.738763988018036

Swift 2.0

xcrun swiftc --version
Apple Swift version 2.0 (swiftlang-700.0.59 clang-700.0.72)
Target: x86_64-apple-darwin15.0.0

xcrun -sdk macosx swiftc -O SwiftSort.swift
./SwiftSort     
Elapsed time: 0.767306983470917

Il semble être le même performance si je compilais avec -Ounchecked .

Swift 3.0

xcrun swiftc --version
Apple Swift version 3.0 (swiftlang-800.0.46.2 clang-800.0.38)
Target: x86_64-apple-macosx10.9

xcrun -sdk macosx swiftc -O SwiftSort.swift
./SwiftSort     
Elapsed time: 0.939633965492249

xcrun -sdk macosx swiftc -Ounchecked SwiftSort.swift
./SwiftSort     
Elapsed time: 0.866258025169373

il semble y avoir eu une régression de la performance de Swift 2.0 à Swift 3.0, et je vois aussi une différence entre -O et -Ounchecked pour la première fois.

Swift 4.0

xcrun swiftc --version
Apple Swift version 4.0.2 (swiftlang-900.0.69.2 clang-900.0.38)
Target: x86_64-apple-macosx10.9

xcrun -sdk macosx swiftc -O SwiftSort.swift
./SwiftSort     
Elapsed time: 0.834299981594086

xcrun -sdk macosx swiftc -Ounchecked SwiftSort.swift
./SwiftSort     
Elapsed time: 0.742045998573303

Swift 4 Améliore à nouveau les performances, tandis que maintenir un écart entre -O et -Ounchecked . -O -whole-module-optimization ne semble pas faire une différence.

C++

#include <chrono>
#include <iostream>
#include <vector>
#include <cstdint>
#include <stdlib.h>

using namespace std;
using namespace std::chrono;

int main(int argc, const char * argv[]) {
    const auto arraySize = 10000000;
    vector<uint32_t> randomNumbers;

    for (int i = 0; i < arraySize; ++i) {
        randomNumbers.emplace_back(arc4random_uniform(arraySize));
    }

    const auto start = high_resolution_clock::now();
    sort(begin(randomNumbers), end(randomNumbers));
    const auto end = high_resolution_clock::now();

    cout << randomNumbers[0] << "\n";
    cout << "Elapsed time: " << duration_cast<duration<double>>(end - start).count() << "\n";

    return 0;
}

Résultats:

Apple Clang 6.0

clang++ --version
Apple LLVM version 6.0 (clang-600.0.54) (based on LLVM 3.5svn)
Target: x86_64-apple-darwin14.0.0
Thread model: posix

clang++ -O3 -std=c++11 CppSort.cpp -o CppSort
./CppSort     
Elapsed time: 0.688969

Apple Clang 6.1.0

clang++ --version
Apple LLVM version 6.1.0 (clang-602.0.49) (based on LLVM 3.6.0svn)
Target: x86_64-apple-darwin14.3.0
Thread model: posix

clang++ -O3 -std=c++11 CppSort.cpp -o CppSort
./CppSort     
Elapsed time: 0.670652

Apple Clang 7.0.0

clang++ --version
Apple LLVM version 7.0.0 (clang-700.0.72)
Target: x86_64-apple-darwin15.0.0
Thread model: posix

clang++ -O3 -std=c++11 CppSort.cpp -o CppSort
./CppSort     
Elapsed time: 0.690152

Apple Clang 8.0.0

clang++ --version
Apple LLVM version 8.0.0 (clang-800.0.38)
Target: x86_64-apple-darwin15.6.0
Thread model: posix

clang++ -O3 -std=c++11 CppSort.cpp -o CppSort
./CppSort     
Elapsed time: 0.68253

Apple Clang 9.0.0

clang++ --version
Apple LLVM version 9.0.0 (clang-900.0.38)
Target: x86_64-apple-darwin16.7.0
Thread model: posix

clang++ -O3 -std=c++11 CppSort.cpp -o CppSort
./CppSort     
Elapsed time: 0.736784

Verdict

au moment de la rédaction de cet article, Le tri de Swift est rapide, mais pas encore aussi rapide que le tri de C++lorsqu'il est compilé avec -O , avec les compilateurs et bibliothèques ci-dessus. Avec -Ounchecked , il semble être aussi rapide que C++ dans Swift 4.0.2 et Apple LLVM 9.0.0.

42
répondu Learn OpenGL ES 2017-11-02 00:27:32
la source

de The Swift Programming Language :

la fonction de tri la bibliothèque standard de Swift fournit une fonction appelée trier, qui trie un tableau de valeurs d'un type connu, basé sur la sortie d'une fermeture de tri que vous fournissez. Une fois terminé, l' processus de tri, la fonction de tri renvoie un nouveau tableau du même type et taille comme l'ancien, avec ses éléments dans le bon trié ordre.

la fonction sort comporte deux déclarations.

la déclaration par défaut qui vous permet de spécifier une fermeture de comparaison:

func sort<T>(array: T[], pred: (T, T) -> Bool) -> T[]

et une deuxième déclaration qui ne prend qu'un seul paramètre (le tableau) et est" hardcoded to use the less-than comparator."

func sort<T : Comparable>(array: T[]) -> T[]

Example:
sort( _arrayToSort_ ) { "151910920" >  }

j'ai testé une version modifiée de votre code dans un terrain de jeu avec la fermeture ajoutée pour que je puisse surveiller la fonction un peu plus de près, et j'ai trouvé qu'avec n réglé à 1000, la fermeture était appelée environ 11 000 fois.

let n = 1000
let x = Int[](count: n, repeatedValue: 0)
for i in 0..n {
    x[i] = random()
}
let y = sort(x) { "151920920" >  }

ce n'est pas une fonction efficace, et je recommande d'utiliser une meilleure implémentation de la fonction de tri.

EDIT:

j'ai regardé la page wikipedia de Quicksort et j'ai écrit une implémentation Swift pour elle. Voici le programme complet que j'ai utilisé (dans un terrain de jeu)

import Foundation

func quickSort(inout array: Int[], begin: Int, end: Int) {
    if (begin < end) {
        let p = partition(&array, begin, end)
        quickSort(&array, begin, p - 1)
        quickSort(&array, p + 1, end)
    }
}

func partition(inout array: Int[], left: Int, right: Int) -> Int {
    let numElements = right - left + 1
    let pivotIndex = left + numElements / 2
    let pivotValue = array[pivotIndex]
    swap(&array[pivotIndex], &array[right])
    var storeIndex = left
    for i in left..right {
        let a = 1 // <- Used to see how many comparisons are made
        if array[i] <= pivotValue {
            swap(&array[i], &array[storeIndex])
            storeIndex++
        }
    }
    swap(&array[storeIndex], &array[right]) // Move pivot to its final place
    return storeIndex
}

let n = 1000
var x = Int[](count: n, repeatedValue: 0)
for i in 0..n {
    x[i] = Int(arc4random())
}

quickSort(&x, 0, x.count - 1) // <- Does the sorting

for i in 0..n {
    x[i] // <- Used by the playground to display the results
}

en utilisant ceci avec n=1000, j'ai trouvé que

  1. quickSort () a été appelé environ 650 fois,
  2. environ 6000 échanges ont été effectués,
  3. et il y a environ 10.000 comparaisons

il semble que la méthode de tri intégrée est (ou est proche de) le tri rapide, et est vraiment lente...

29
répondu David Skrundz 2014-06-16 18:06:27
la source

à partir du Xcode 7, vous pouvez activer Fast, Whole Module Optimization . Cela devrait accroître vos performances immédiatement.

enter image description here

15
répondu Antoine 2015-06-11 19:56:04
la source

Swift performances de l'ensemble revisité:

j'ai écrit mon propre benchmark comparant Swift avec C/Objective-C. Mon benchmark calcule des nombres premiers. Il utilise le tableau des nombres premiers précédents pour chercher des facteurs premiers dans chaque nouveau candidat, il est donc assez rapide. Cependant, il fait des tonnes de lecture de tableau, et moins d'écriture aux tableaux.

j'ai fait à l'origine ce benchmark par rapport à Swift 1.2. J'ai décidé de mettre à jour le projet et de l'exécuter contre Swift 2.0.

le projet vous permet de choisir entre l'utilisation de tableaux swift normaux et l'utilisation de tampons mémoire non sécurisés Swift en utilisant la sémantique des tableaux.

pour C / Objective-C, vous pouvez choisir D'utiliser NSArrays, ou c malloc'ed arrays.

les résultats des tests semblent assez similaires avec l'optimisation la plus rapide, la plus petite ([-0s]) ou la plus rapide, l'optimisation agressive ([-0fast]).

Swift 2.0 performance est toujours horrible avec l'optimisation du code est désactivée, alors que la performance C/Objective-C n'est que modérément plus lente.

La ligne de fond est que C malloc avais tableau basé sur les calculs sont les plus rapides, par une modeste marge

Swift avec des tampons dangereux prend environ 1,19 X-1,20 X de plus que les tableaux c malloc'd en utilisant la plus rapide, la plus petite optimisation de code. la différence semble légèrement moindre avec une optimisation rapide et agressive (Swift prend plus de 1,18 x à 1,16 x de plus que C.

si vous utilisez des tableaux Swift réguliers, la différence avec C est légèrement supérieure. (Swift prend ~1,22 à 1,23 de plus.)

les réseaux Swift réguliers sont DRAMATICALLY plus rapides qu'ils ne L'étaient dans Swift 1.2/Xcode 6. Leurs performances sont si proches des tableaux basés sur des tampons non sécurisés de Swift que l'utilisation de tampons de mémoire non sécurisés ne semble plus vraiment valoir la peine, ce qui est énorme.

BTW, Objective-NSArray la performance craint. Si vous allez utiliser les objets de conteneur natifs dans les deux langues, Swift est dramatiquement plus rapide.

vous pouvez consulter mon projet sur github à SwiftPerformanceBenchmark

il a une interface utilisateur simple qui rend la collecte des statistiques assez facile.

il est intéressant de noter que le tri semble être un peu plus rapide chez Swift qu'en C maintenant, mais cet algorithme du nombre premier est encore plus rapide dans Swift.

8
répondu Duncan C 2016-02-26 04:31:03
la source

la principale question qui est mentionnée par d'autres mais pas suffisamment appelée est que -O3 ne fait rien du tout dans Swift (et ne l'a jamais fait) de sorte qu'une fois compilé, il est effectivement non optimisé ( -Onone ).

Les noms des options

ont changé au fil du temps de sorte que certaines autres réponses ont des options obsolètes pour les options de construction. Les options courantes correctes (Swift 2.2) sont:

-Onone // Debug - slow
-O     // Optimised
-O -whole-module-optimization //Optimised across files

optimisation de module entier a une compilation plus lente, mais peut optimisez l'ensemble des fichiers du module, c'est-à-dire dans chaque cadre et dans le code d'application proprement dit, mais pas entre eux. Vous devriez l'utiliser pour tout ce qui est critique à la performance)

vous pouvez également désactiver les contrôles de sécurité pour encore plus de vitesse, mais avec toutes les affirmations et conditions préalables non seulement désactivé mais optimisé sur la base qu'ils sont corrects. Si vous frappez une assertion cela signifie que vous êtes dans un comportement non défini. Utiliser avec une extrême prudence et seulement si vous déterminez que l'augmentation de la vitesse en vaut la peine (par des essais). Si vous le trouvez utile pour certains codes, je recommande de séparer ce code dans un cadre séparé et de désactiver uniquement les contrôles de sécurité pour ce module.

5
répondu Joseph Lord 2016-04-13 13:58:05
la source
func partition(inout list : [Int], low: Int, high : Int) -> Int {
    let pivot = list[high]
    var j = low
    var i = j - 1
    while j < high {
        if list[j] <= pivot{
            i += 1
            (list[i], list[j]) = (list[j], list[i])
        }
        j += 1
    }
    (list[i+1], list[high]) = (list[high], list[i+1])
    return i+1
}

func quikcSort(inout list : [Int] , low : Int , high : Int) {

    if low < high {
        let pIndex = partition(&list, low: low, high: high)
        quikcSort(&list, low: low, high: pIndex-1)
        quikcSort(&list, low: pIndex + 1, high: high)
    }
}

var list = [7,3,15,10,0,8,2,4]
quikcSort(&list, low: 0, high: list.count-1)

var list2 = [ 10, 0, 3, 9, 2, 14, 26, 27, 1, 5, 8, -1, 8 ]
quikcSort(&list2, low: 0, high: list2.count-1)

var list3 = [1,3,9,8,2,7,5]
quikcSort(&list3, low: 0, high: list3.count-1) 

Ceci est mon Blog sur le Tri Rapide- Github échantillon de Tri Rapide

vous pouvez jeter un oeil à L'algorithme de partitionnement de Lomuto dans Partitionnement de la liste. Écrit en Swift

4
répondu Abo3atef 2018-03-25 20:30:49
la source