Is Swift really slow at dealing with numbers?
当我在玩一个快速教程时,我开始编写一个自定义的
写完后,我意识到它工作正常,但发现在一些相当大的数字上执行
所以我在objc中编写了相同的代码,代码执行速度快得多(66x的系数)。
这里是SWIFT代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | 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; } } |
以及OBJC代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | @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 |
在
1 2 3 4 5 6 7 8 9 10 | 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"); |
这产生:
1 2 | [1040101022027, 1040101022039, 1040101022057, 1040101022099, 1040101022153] took: 3953.82004976273ms [1040101022027, 1040101022039, 1040101022057, 1040101022099, 1040101022153] took: 66.4250254631042ms |
我知道我可以在这里用
有人能告诉我为什么这个快速代码慢得多吗?66X系数是相当可怕的,只会随着我增加范围而变得更糟。
以下是Swift编译器代码生成的优化级别(您可以在构建设置中找到它们):
1 2 3 | [-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. |
使用您的代码,我可以在不同的优化级别获得这些时间:
[奥诺]
1 2 | Swift: 6110.98903417587ms Objc: 134.006023406982ms |
[-O]
1 2 | Swift: 89.8249745368958ms Objc: 85.5680108070374ms |
[ Ofast ]
1 2 | Swift: 77.1470069885254ms Objc: 76.3399600982666ms |
请记住,Ofast是有风险的。例如,它会默默地忽略整数和数组溢出,产生无意义的结果,所以如果你选择使用它,你必须保证你的程序中不可能出现溢出。
感谢@sjeohp的评论,这基本上是问题的答案。
我尝试用
在
1 2 | [1040101022027, 1040101022039, 1040101022057, 1040101022099, 1040101022153] took: 63.211977481842ms [1040101022027, 1040101022039, 1040101022057, 1040101022099, 1040101022153] took: 60.0320100784302ms |
再次感谢@sjeohp抓到这个!