2014-06-11 16 views
30

Als ich mit einem schnellen Tutorial herumspielte, fing ich an, eine benutzerdefinierte isPrime Methode zu schreiben, um zu überprüfen, ob eine gegebene Int Prime ist oder nicht.Ist Swift wirklich langsam im Umgang mit Zahlen?

Nach dem Schreiben Ich erkennen, dass es richtig funktioniert, aber fand es ein bisschen langsam auf einige ziemlich große Zahl durchzuführen isPrime (noch viel niedriger als Int.max).

Also schrieb ich das gleiche Stück Code in objc und der Code wurde viel schneller ausgeführt (ein Faktor von 66x). Hier

ist der SWIFT-Code:

class Swift { 
    class func isPrime(n:Int) -> Bool { 
     let sqr : Int = Int(sqrt(Double(n))) + 1 
     for i in 2...sqr { 
      if n % i == 0 { 
       return false 
      } 
     } 
     return true; 
    } 
    class func primesInRange(start:Int, end:Int) -> Int[] { 
     var primes:Int[] = Int[]() 
     for n in start...end { 
      if self.isPrime(n) { 
       primes.append(n) 
      } 
     } 
     return primes; 
    } 
} 

Und der objc Code:

@implementation Utils 

+ (BOOL)isPrime:(NSUInteger)n { 
    NSInteger sqr = (NSUInteger)(sqrt(n))+1; 
    for (NSUInteger i = 2; i < sqr; ++i) { 
     if (n % i == 0) { 
      return false; 
     } 
    } 
    return YES; 
} 

+ (NSArray*)primesInRange:(NSUInteger)start end:(NSUInteger)end { 
    NSMutableArray* primes = [NSMutableArray array]; 
    for (NSUInteger i = start; i <= end; ++i) { 
     if ([self isPrime:i]) 
      [primes addObject:@(i)]; 
    } 

    return primes.copy; 
} 

@end 

Und in main.swift:

let startDateSwift = NSDate.date() 
let swiftPrimes = Swift.primesInRange(1_040_101_022_000, end: 1_040_101_022_200) 
let elapsedSwift = NSDate.date().timeIntervalSinceDate(startDateSwift)*1000 

let startDateObjc = NSDate.date() 
let objcPrimes = Utils.primesInRange(1_040_101_022_000, end: 1_040_101_022_200) 
let elapsedObjc = NSDate.date().timeIntervalSinceDate(startDateObjc)*1000 

println("\(swiftPrimes) took: \(elapsedSwift)ms"); 
println("\(objcPrimes) took: \(elapsedObjc)ms"); 

Dies erzeugt:

[1040101022027, 1040101022039, 1040101022057, 1040101022099, 1040101022153] took: 3953.82004976273ms 
[1040101022027, 1040101022039, 1040101022057, 1040101022099, 1040101022153] took: 66.4250254631042ms 

Ich weiß, dass ich extension auf Int hier verwendet haben könnte, um zu überprüfen, ob eine Zahl prime ist, aber ich wollte beide Code sehr ähnlich sein.

Kann mir jemand sagen, warum dieser schnelle Code so viel langsamer ist? Der 66x-Faktor ist ziemlich gruselig und wird nur noch schlimmer, wenn ich die Reichweite vergrößere.

+0

Haben Sie sich den generierten Assembler-Code angesehen? Ich denke, das wäre ziemlich lehrreich. – cmaster

+0

Zuerst die Reihenfolge der Tests umkehren und prüfen, ob die Ergebnisse identisch sind. Ich sehe nicht, warum es in diesem Fall wichtig wäre, aber in anderen Kontexten könnten Sie Caching-Effekte usw. bekommen. –

+1

@cmaster xcode 6 (6A215l) scheint noch nicht 'Assembly View' für Swif zu unterstützen. @ "Tom Zych" ja das habe ich auch versucht aber das selbe ergebnis. Objc gerade läuft schnell in beliebiger Reihenfolge. – apouche

Antwort

26

Hier sind Optimierungsstufen für die Code-Generierung des Swift-Compiler (Sie können sie in Build-Einstellungen zu finden):

[-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. 

Arbeiten mit dem Code habe ich diese Zeiten auf verschiedenen Ebenen der Optimierung:

[ -Onone]

Swift: 6110.98903417587ms 
Objc: 134.006023406982ms 

[-O]

Swift: 89.8249745368958ms 
Objc: 85.5680108070374ms 

[-Ofast]

Swift: 77.1470069885254ms 
Objc: 76.3399600982666ms 

Beachten Sie, dass -Ofast kommt mit Risiken ist. z.B. Es ignoriert automatisch Integer- und Array-Überläufe, was zu unsinnigen Ergebnissen führt. Wenn Sie sich entscheiden, es zu verwenden, müssen Sie sich selbst garantieren, dass Überläufe in Ihrem Programm nicht möglich sind.

+11

Also für die Standard-Produktions-Level-Optimierung, schnell im Umgang mit Zahlen ist * nicht * die 2x schneller, dass Apfel bei wwdc !? – Ryan

+9

@ryan Ich bin mir sicher, dass sie einen Testfall sehr sorgfältig gewählt haben. – Kevin

+16

@ryan es läuft schneller innerhalb der Realität Verzerrungsfeld. – hobbs

5

Dank an @sjeohp für seinen Kommentar, der im Grunde die Antwort auf die Frage ist.

Ich habe versucht, den Code an die aggressivste Art und Weise zu optimieren in Release sowohl für LLVM und Swift Optimierungen:

enter image description here

enter image description here

das Projekt in Release Zusammengestellt und bekam:

[1040101022027, 1040101022039, 1040101022057, 1040101022099, 1040101022153] took: 63.211977481842ms 
[1040101022027, 1040101022039, 1040101022057, 1040101022099, 1040101022153] took: 60.0320100784302ms 

Nochmals, danke @sjeohp für das Fangen!

Verwandte Themen