Questa domanda riguarda la velocità di di accedere agli elementi di array e slice, non l'efficienza di passarli a funzioni come argomenti.Array vs Slice: velocità di accesso
mi aspetto array essere più veloce di fette nella maggior parte dei casi, perché una fetta è una struttura di dati che descrive una sezione contigua di una matrice e quindi ci può essere un passaggio in più coinvolti quando si accede elementi di una fetta (indirettamente gli elementi della matrice sottostante).
Così ho scritto un piccolo test per confrontare un lotto di operazioni semplici. Ci sono 4 funzioni di riferimento, i primi 2 test di un globale fetta e un allineamento globale, gli altri 2 test di un locale fetta e una matrice locale:
var gs = make([]byte, 1000) // Global slice
var ga [1000]byte // Global array
func BenchmarkSliceGlobal(b *testing.B) {
for i := 0; i < b.N; i++ {
for j, v := range gs {
gs[j]++; gs[j] = gs[j] + v + 10; gs[j] += v
}
}
}
func BenchmarkArrayGlobal(b *testing.B) {
for i := 0; i < b.N; i++ {
for j, v := range ga {
ga[j]++; ga[j] = ga[j] + v + 10; ga[j] += v
}
}
}
func BenchmarkSliceLocal(b *testing.B) {
var s = make([]byte, 1000)
for i := 0; i < b.N; i++ {
for j, v := range s {
s[j]++; s[j] = s[j] + v + 10; s[j] += v
}
}
}
func BenchmarkArrayLocal(b *testing.B) {
var a [1000]byte
for i := 0; i < b.N; i++ {
for j, v := range a {
a[j]++; a[j] = a[j] + v + 10; a[j] += v
}
}
}
Ho eseguito il test di più volte, ecco l'uscita tipica (go test -bench .*
):
BenchmarkSliceGlobal 300000 4210 ns/op
BenchmarkArrayGlobal 300000 4123 ns/op
BenchmarkSliceLocal 500000 3090 ns/op
BenchmarkArrayLocal 500000 3768 ns/op
Analisi dei risultati:
Accesso al fetta globale è leggermente più lento rispetto l'accesso alla gamma globale che è come mi aspettavo:
4210
vs 4123
ns/OP
Ma di accesso a fetta locale è significativamente più veloce l'accesso alla matrice locale:
3090
vs 3768
ns/OP
La mia domanda è: Qual è la ragione di questo?
Note
Ho provato variando le seguenti cose, ma nessuno ha cambiato il risultato:
- la dimensione della matrice/slice (provato 100, 1000, 10000)
- dell'ordine delle funzioni benchmark
- il tipo di elemento dell'array/slice (provato
byte
eint
)
Ci sono diversi fattori che influenzano tali micro benchmark: controllo dei vincoli, allocazione (heap, stack), generazione di codice, ottimizzazione degli spioncini, ecc. Dai un'occhiata all'output generato dell'assieme in condizioni diverse come il controllo dei vincoli disabilitato o le ottimizzazioni disabilitate. – Volker
È interessante notare che se aggiungi un [puntatore all'array] (http://play.golang.org/p/nyynQgndDl) ai benchmark, vedrai che si comportano all'incirca come slice. –