Go
Meydan okuma 3 - Performance
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.
Örnek çözümü göster
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)
}
Kendini test et
-
<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
- Daha kısa yazılır
- Ondalık sayıları da destekler
Cevabı göster
Sayıyı var olan bir bayt dilimine yazar, ara string oluşturmaz — Itoa her sayı için yeni bir string ayırır; AppendInt verilen tampona ekler ve tampon yeterince büyükse ayırma yapmaz.
-
Tampona ekle
buf = strconv.____(buf, int64(x), 10)
Cevabı göster
buf = strconv.AppendInt(buf, int64(x), 10)
-
Yöntem ve maliyet
- s += ...
- Her adımda yeni string
- strconv.Itoa
- Sayı başına bir string
- AppendInt
- Tampona yazar
- make(..., 0, cap)
- Önceden kapasite
Sıradaki ders: Meydan okuma 4 - Database