Reputation: 94
Swift provide a for-in style for-loops to substitute C-style for-loops. We can also use this kind of for-in loops with Range
and ClosedRange
.
for i in 0..<100 {
// do something.
}
However, there are some performance issues when using for-in loops with ranges, especially when there are nested for-loops.
I use XCTest measure
to test three kinds of loops:
ClosedRange
Range
final class LeetcodeSolutionsTests: XCTestCase {
var count: Int = 1000
func testForInClosedRange() {
// Time: 1.016 sec
measure {
for i in 1...count {
for j in 1...count {
let _ = i + j
}
}
}
}
func testForInRange() {
// Time: 0.542 sec
measure {
for i in 1...count {
for j in 1..<(count + 1) {
let _ = i + j
}
}
}
}
func testWhile() {
// Time: 0.015 sec
measure {
for i in 1...count {
var j = 1
while j < count + 1 {
let _ = i + j
j += 1
}
}
}
}
}
From the example, the for-in loop with Range
is 2 times faster than the for-in loop with ClosedRange
. And the while loop is much faster than both of them.
I guess for-in loops will do some extra works, and it makes sense that there would be some subtle performance differences. What I don't expect is that the performance differences are so huge.
Upvotes: 0
Views: 258
Reputation: 10199
Your problem appears only in a Debug configuration, because the compiler generates a huge amount of access checking code.
If you
you get the very same results for each kind of loop:
func measure(txt:String = #function, c:()->()) {
let start=Date()
c()
let end = Date()
let duration = end.timeIntervalSinceReferenceDate-start.timeIntervalSinceReferenceDate
print ("\(txt) - Duration: \(duration)")
}
final class LeetcodeSolutionsTests {
var count: Int = 1000
func testForInClosedRange() {
// Time: 0.001672 sec
var result:Int = 0
measure {
for i in 1...count {
for j in 1...count {
result += i + j
}
}
}
print (result)
}
func testForInRange() {
// Time: 0.001671
var result:Int = 0
measure {
for i in 1...count {
for j in 1..<(count + 1) {
result += i + j
}
}
}
print (result)
}
func testWhile() {
// Time: 0.001670 sec
var result:Int = 0
measure {
for i in 1...count {
var j = 1
while j < count + 1 {
result += i + j
j += 1
}
}
}
print (result)
}
}
let t = LeetcodeSolutionsTests()
t.testForInClosedRange()
t.testForInRange()
t.testWhile()
Which then gives you:
testForInClosedRange() - Duration: 0.0016720294952392578
1001000000
testForInRange() - Duration: 0.0016709566116333008
1001000000
testWhile() - Duration: 0.0016709566116333008
1001000000
Upvotes: 2