My results:
-Onone (None)
plain for loop with guard
Elapsed time: 0.0563530325889587
plain for loop with if
Elapsed time: 0.0631130337715149
where test
Elapsed time: 0.0661619901657104
eager filter test
Elapsed time: 0.684610962867737
lazy filter test
Elapsed time: 0.640420973300934
Program ended with exit code: 0
-O (Fast)
plain for loop with guard
Elapsed time: 0.00411999225616455
plain for loop with if
Elapsed time: 0.00422400236129761
where test
Elapsed time: 0.00419700145721436
eager filter test
Elapsed time: 0.033439040184021
lazy filter test
Elapsed time: 0.00690501928329468
Program ended with exit code: 0
Code:
public func timetest(_ note: String, block: () -> Void) {
let date = NSDate()
block()
let timeInterval = NSDate().timeIntervalSince(date)
print(note); print("Elapsed time: \(timeInterval)")
}
let count = 4_000_000
let range = 1...count
timetest("plain for loop with guard") {
for i in range {
guard i % 2 != 0 else { continue }
doSomething()
}
}
timetest("plain for loop with if") {
for i in range {
if i % 2 == 0 { continue }
doSomething()
}
}
timetest("where test") {
for i in range where i % 2 == 0 {
doSomething()
}
}
timetest("eager filter test") {
for i in range.filter({ $0 % 2 == 0 }) {
doSomething()
}
}
timetest("lazy filter test") {
for i in range.lazy.filter({ $0 % 2 == 0 }) {
doSomething()
}
}
> On Jun 9, 2016, at 4:27 AM, Charlie Monroe <[email protected]> wrote:
>
>>
>> On Jun 9, 2016, at 10:29 AM, Brent Royal-Gordon <[email protected]>
>> wrote:
>>
>>> I've taken the time to run a test, going through milion numbers (several
>>> times) using:
>>>
>>> for i in arr { if i % 2 == 0 { continue } }
>>> for i in arr where i % 2 == 0 { }
>>> for i in arr.filter({ $0 % 2 == 0 }) { }
>>> for i in arr.lazy.filter({ $0 % 2 == 0 }) { }
>>>
>>> Results:
>>>
>>> - plain for loop with if-continue: 27.19 seconds (+1.76%)
>>> - with where: 26.72 seconds (+0.00%)
>>> - .filter: 44.73 seconds (+67.40%)
>>> - .lazy.filter: 31.66 seconds (+18.48%)
>>
>> This is great data. I have a hard time imagining a little compiler work
>> couldn't make if-continue as fast as for-where, but lazy.filter might be a
>> taller order for it, and optimizing plain filter could actually change
>> behavior.
>>
>> A month or two ago, I actually fell into the "just use the higher-order
>> functions" camp on this question, but I've been rethinking that more and
>> more lately. Between the trailing closure incompatibility, the need to
>> remember to use `lazy` to get decent performance, and now the noticeable
>> speed difference even *with* lazy, I'm no longer convinced that answer is
>> good enough.
>
> There will IMHO always be noticeable overhead since you're calling a function
> which is then invoking a closure. When you look at what that means:
>
> - thunks generated around the invocation, which are a few instructions
> - new stack frame for each call (correct me if I'm wrong).
>
> So instead of a single `i % 2 == 0` (which is just 2-3 instructions,
> depending on the architecture and optimization settings), it will invoke the
> closure milion times, if the array contains a milion members.
>
> Maybe I'm over-optimizing, but 18% seemed like a lot to me.
>
>
>>
>> (Though I do think `while` is probably too niche to bother with as a
>> first-class feature, and I am open to if-continue on the `where` clause.)
>>
>> --
>> Brent Royal-Gordon
>> Architechies
_______________________________________________
swift-evolution mailing list
[email protected]
https://lists.swift.org/mailman/listinfo/swift-evolution