Ta sekcja zawiera wytyczne dotyczące pisania kodu z perspektywy Golang, które są korzystne dla poprawy wydajności.

Preferuj strconv nad fmt

Podczas konwertowania typów podstawowych na ciągi znaków lub z ciągów znaków na typy podstawowe, strconv działa szybciej niż fmt.

Nie zalecane:

for i := 0; i < b.N; i++ {
  s := fmt.Sprint(rand.Int())
}

Zalecane:

for i := 0; i < b.N; i++ {
  s := strconv.Itoa(rand.Int())
}

Unikaj konwertowania ciągów znaków na bajty

Unikaj wielokrotnego tworzenia fragmentu bajtów z ustalonego ciągu znaków. Zamiast tego wykonaj konwersję raz i przechwyć wynik.

Nie zalecane:

for i := 0; i < b.N; i++ {
  w.Write([]byte("Witaj, świecie"))
}

Zalecane:

data := []byte("Witaj, świecie")
for i := 0; i < b.N; i++ {
  w.Write(data)
}

Określ pojemność kontenera

Określ pojemność kontenera, jeśli to możliwe, aby zarezerwować pamięć dla kontenera. Pozwala to zminimalizować kolejne alokacje (poprzez kopiowanie i zmianę rozmiaru kontenera) podczas dodawania elementów.

Wskazówka dotycząca pojemności mapy

W większości przypadków podaj informację o pojemności podczas inicjalizacji za pomocą make().

make(map[T1]T2, wskazówka)

Podanie wskazówki dotyczącej pojemności do make() spowoduje próbę zmiany rozmiaru mapy podczas inicjalizacji, co zmniejszy realokację pamięci podczas dodawania elementów do mapy.

Należy pamiętać, że w przeciwieństwie do przekrojów, wskazówka dotycząca pojemności mapy nie gwarantuje pełnej prealokacji, ale służy do oszacowania liczby kubełków hashmapy wymaganych. Dlatego alokacja może nadal wystąpić podczas dodawania elementów do mapy, nawet po określeniu pojemności mapy.

Nie zalecane:

m := make(map[string]os.FileInfo)

files, _ := os.ReadDir("./pliki")
for _, f := range files {
    m[f.Name()] = f
}

// m jest tworzona bez wskazówki dotyczącej rozmiaru; może to prowadzić do większej alokacji pamięci w czasie wykonania.

Zalecane:

files, _ := os.ReadDir("./pliki")

m := make(map[string]os.FileInfo, len(files))
for _, f := range files {
    m[f.Name()] = f
}

// m jest tworzona z wskazówką dotyczącą rozmiaru; może to prowadzić do mniejszej alokacji pamięci w czasie wykonania.

Określenie pojemności przekroju

W większości przypadków podaj informację o pojemności podczas inicjalizacji przekroju za pomocą make(), zwłaszcza podczas dodawania elementów do przekroju.

make([]T, długość, pojemność)

W przeciwieństwie do map, pojemność przekroju to nie tylko wskazówka: kompilator zarezerwuje wystarczającą ilość pamięci dla podanej pojemności przekroju w make(), co oznacza, że kolejne operacje append() prowadzą do zerowej alokacji pamięci (do momentu gdy długość przekroju osiągnie jego pojemność, po czym każde dodanie elementu może spowodować zmianę rozmiaru w celu pomieszczenia dodatkowych elementów).

Nie zalecane:

for n := 0; n < b.N; n++ {
  data := make([]int, 0)
  for k := 0; k < rozmiar; k++{
    data = append(data, k)
  }
}

Zalecane:

for n := 0; n < b.N; n++ {
  data := make([]int, 0, rozmiar)
  for k := 0; k < rozmiar; k++{
    data = append(data, k)
  }
}