Meydan okuma 3 - Performance
- Go kursu
- İleri seviye
- Ders 67/68
- 8 dk
Benchmark ve pprof ile darboğaz bulan bir analiz yazarsın.
Meydan okuma: ayırmayı azalt
Elinde sayıları virgülle birleştiren yavaş bir fonksiyon var:
func yavas(n []int) string {
s := ""
for i, x := range n {
if i > 0 { s += "," }
s += strconv.Itoa(x)
}
return s
}Her += yeni bir string ayırır. Görevin: aynı çıktıyı strings.Builder ve strconv.AppendInt ile çok daha az ayırmayla üretmek ve farkı testing.AllocsPerRun ile ölçmek.
Plan
Önce kapasite ayır: her sayı için en fazla ~20 bayt yeter, buf := make([]byte, 0, len(n)*21). Döngüde virgül ve strconv.AppendInt(buf, int64(x), 10) ekle; sonunda string(buf) döndür. Ölçüm için iki fonksiyonu da testing.AllocsPerRun(100, ...) içinde çalıştır ve sonuçları karşılaştır. Çıktıların eşit olduğunu da kontrol et.
Uygulama Hızlı sürüm
yavas ve hizli fonksiyonlarını yaz. n := []int{1, 22, 333, 4444} için iki çıktının eşit olduğunu ve hizli'nin ayırma sayısının yavas'tan az olduğunu tek satırda yazdır.
Başlangıç kodu
package main
import (
"fmt"
"strconv"
"testing"
)
func main() {
// buraya yaz
}Örnek çözüm
package main
import (
"fmt"
"strconv"
"testing"
)
func yavas(n []int) string {
s := ""
for i, x := range n {
if i > 0 {
s += ","
}
s += strconv.Itoa(x)
}
return s
}
func hizli(n []int) string {
buf := make([]byte, 0, len(n)*21)
for i, x := range n {
if i > 0 {
buf = append(buf, ',')
}
buf = strconv.AppendInt(buf, int64(x), 10)
}
return string(buf)
}
var sink string
func main() {
n := []int{1, 22, 333, 4444}
a := testing.AllocsPerRun(100, func() { sink = yavas(n) })
b := testing.AllocsPerRun(100, func() { sink = hizli(n) })
fmt.Println(yavas(n) == hizli(n), b < a)
}Beklenen çıktı
true true
Soru ve cevaplar
Dersin sorularını cevaplarıyla birlikte inceleyebilirsin. Kendini denemek istersen dersi interaktif olarak çöz.
1 <code>strconv.AppendInt</code>'i <code>Itoa</code>'dan avantajlı yapan nedir?
- Eşzamanlı çalışır
- Sayıyı var olan bir bayt dilimine yazar, ara string oluşturmaz Doğru cevap
- Daha kısa yazılır
- Ondalık sayıları da destekler
Açıklama: Itoa her sayı için yeni bir string ayırır; AppendInt verilen tampona ekler ve tampon yeterince büyükse ayırma yapmaz.
2 Tampona ekle
buf = strconv.____(buf, int64(x), 10)
buf = strconv.AppendInt(buf, int64(x), 10)
Açıklama: AppendInt sayının ondalık gösterimini mevcut bayt dilimine ekler.
3 Yöntem ve maliyet
| Kavram | Anlamı |
|---|---|
s += ... |
Her adımda yeni string |
strconv.Itoa |
Sayı başına bir string |
AppendInt |
Tampona yazar |
make(..., 0, cap) |
Önceden kapasite |