Is there any performance difference between two examples below:
1.
var slice []int{ ... huge list of items... }
for i:=0; i<len(slice); i { .... do something ....}
2.
var slice []int{ ... huge list of items... }
sliceLen := len(slice)
for i:=0; i<sliceLen; i { .... do something ....}
Are the condition expressions in "for" statement evaluated at each iteration or only once?
CodePudding user response:
TLDR: There is almost no difference
Good way how to test your problem is benchmarking provided by standard testing
library
Create test file eg: forcycle_test.go
package perftest
import (
"testing"
)
func BenchmarkLenInside(b *testing.B) {
testData := make([]int, 1000000)
for i := 0; i < b.N; i {
// Benchmarked code start
for j := 0; j < len(testData); j {
doSth(testData[j])
}
// end
}
}
func BenchmarkLenOutside(b *testing.B) {
testData := make([]int, 1000000)
for i := 0; i < b.N; i {
// Benchmarked code start
sliceLen := len(testData)
for j := 0; j < sliceLen; j {
doSth(testData[j])
}
// end
}
}
func doSth(n int) {
_ = n n
}
Run benchmark
go test -bench .
Example output
goos: linux
goarch: amd64
pkg: forperf
BenchmarkLenInside-6 4543 259117 ns/op
BenchmarkLenOutside-6 4620 258069 ns/op
PASS
ok forperf 3.811s
The benchmark function must run the target code b.N times. During benchmark execution, b.N is adjusted until the benchmark function lasts long enough to be timed reliably.
As you can see in this benchmark run when you write len
function as part of for cycle, it is just slightly slower then version out of cycle.
Type | b.N before timed | Avg time per b.N iteration |
---|---|---|
Len in | 4543 | 259117 ns |
Len out | 4620 | 258069 ns |
Note that several runs gives you different results where len in
is A
and len out
is B
A < B
or A ≈ B
or even A > B
is possible.
CodePudding user response:
Are the condition expressions in "for" statement evaluated at each iteration or only once?
The specification says that the condition is evaluated before each iteration.
Because the value of i
changes on each iteration, it makes sense the conditions i<len(slice)
and i<sliceLen
are evaluated before each iteration.
The compiler can hoist parts of the condition expression evaluation out of the loop as long as the resulting program executes as if the expression is evaluated every time. For example, the compiler can load len(slice)
or sliceLen
to a register before the loop and use that register in the loop.
Is there any performance difference between two examples below
Both code snippets compare variable i
to a value read from a variable. In the first snippet, the value is read from the slice header length field. See Slices: usage and internals if you are not familiar with how a slice is implemented.
The performance should be similar if not identical.