Pertanyaan Apakah Swift benar-benar lambat dalam berurusan dengan angka?


Saat saya bermain-main dengan tutorial cepat, saya mulai menulis sebuah kebiasaan isPrime metode untuk memeriksa apakah diberikan Int Perdana atau tidak.

Setelah menulisnya, saya menyadari itu berfungsi dengan baik tetapi ternyata agak lambat untuk melakukan isPrime pada beberapa cukup jumlah besar (masih jauh lebih rendah saat itu Int.max).

Jadi saya menulis potongan kode yang sama dalam objc dan kode dieksekusi lebih cepat (faktor 66x).

Ini kode cepatnya:

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;
    }
}

Dan kode objc:

@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

Dan masuk 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");

Ini menghasilkan:

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

Saya tahu bahwa saya bisa menggunakan extension di Int di sini untuk memeriksa apakah suatu bilangan prima, tetapi saya ingin kedua kode itu sangat mirip.

Adakah yang bisa memberitahu saya mengapa kode cepat ini jauh lebih lambat? Faktor 66x cukup menakutkan dan hanya semakin memburuk saat saya menaikkan kisaran.


32
2018-06-11 12:02


asal


Jawaban:


Berikut adalah tingkat optimasi untuk generasi kode kompilator Swift (Anda dapat menemukannya di Pengaturan Build):

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

Menggunakan kode Anda, saya mendapatkan waktu ini pada tingkat pengoptimalan yang berbeda:

[-Onone]

Swift: 6110.98903417587ms
Objc:  134.006023406982ms

[-HAI]

Swift: 89.8249745368958ms
Objc:  85.5680108070374ms

[- Cepat]

Swift: 77.1470069885254ms
Objc:  76.3399600982666ms

Perlu diingat bahwa -Otah datang dengan risiko. misalnya Ini akan diam-diam mengabaikan integer dan luapan array, menghasilkan hasil yang tidak masuk akal, jadi jika Anda memilih untuk menggunakannya Anda harus menjamin diri sendiri bahwa luapan tidak mungkin dalam program Anda.


26
2018-06-11 12:35



Kredit untuk @sjeohp atas komentarnya yang pada dasarnya adalah jawaban atas pertanyaan itu.

Saya mencoba mengoptimalkan kode ke cara paling agresif di Release untuk optimasi LLVM dan Swift:

enter image description here

enter image description here

Menyusun proyek di Release dan mendapatkan:

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

Sekali lagi, terima kasih @sjeohp untuk menangkap ini!


5
2018-06-11 12:36