0Pricing
Go Academy · Lekcja

Uruchamianie goroutines

Słowo kluczowe go, cykl życia goroutines i WaitGroups

Uruchamianie goroutines to bezpłatna lekcja Go Academy na CoddyKit. To lekcja 1 z 4. Możesz przeczytać całą lekcję poniżej za darmo — a potem ćwiczyć ją interaktywnie w przeglądarce z wbudowanym edytorem kodu i tutorem AI dostępnym 24/7. To część ścieżki edukacyjnej Go Academy, a Twój postęp synchronizuje się między webem a aplikacją CoddyKit. Kurs Go Academy zawiera 4 lekcji w sumie.

Czym jest gorutyna?

Gorutyna to lekka funkcja wykonywana współbieżnie i zarządzana przez środowisko uruchomieniowe Go. Gorutyny są znacznie tańsze niż wątki systemu operacyjnego — można uruchamiać ich tysiące:

  • Uruchamianie za pomocą słowa kluczowego go
  • Początkowy stos ma około 2 KB i rośnie dynamicznie
  • Planowaniem zajmuje się środowisko uruchomieniowe Go, a nie system operacyjny
  • Komunikacja odbywa się przez kanały, a nie przez pamięć współdzieloną

Słowo kluczowe go

Dowolne wywołanie funkcji można poprzedzić słowem kluczowym go, aby uruchomić je jako gorutynę:

package main
import ("fmt"; "time")

func greet(name string) {
    fmt.Printf("Hello, %s!\n", name)
}

func main() {
    go greet("Alice")   // runs concurrently
    go greet("Bob")     // runs concurrently
    time.Sleep(100 * time.Millisecond) // wait for goroutines
    fmt.Println("done")
}

Cykl życia gorutyny

Gorutyna rozpoczyna działanie w chwili wykonania instrukcji go i kończy je, gdy jej funkcja zwróci wynik. Jeśli funkcja main zakończy działanie, wszystkie gorutyny zostają zakończone:

package main
import ("fmt"; "time")

func worker(id int) {
    fmt.Printf("Worker %d starting\n", id)
    time.Sleep(time.Duration(id) * 50 * time.Millisecond)
    fmt.Printf("Worker %d done\n", id)
}

func main() {
    for i := 1; i <= 3; i++ {
        go worker(i)
    }
    time.Sleep(300 * time.Millisecond) // naive wait
}

sync.WaitGroup do koordynacji

Zamiast funkcji sleep należy używać sync.WaitGroup do oczekiwania na zakończenie gorutyn:

package main
import ("fmt"; "sync")

func worker(id int, wg *sync.WaitGroup) {
    defer wg.Done()  // signal completion
    fmt.Printf("Worker %d working\n", id)
}

func main() {
    var wg sync.WaitGroup
    for i := 1; i <= 5; i++ {
        wg.Add(1)           // register one goroutine
        go worker(i, &wg)
    }
    wg.Wait()               // block until all Done()
    fmt.Println("all workers finished")
}

Anonimowe gorutyny

Anonimową funkcję można uruchomić bezpośrednio jako gorutynę — jest to przydatne w przypadku wbudowanych zadań współbieżnych:

package main
import ("fmt"; "sync")

func main() {
    var wg sync.WaitGroup
    for i := 0; i < 3; i++ {
        i := i  // capture loop variable
        wg.Add(1)
        go func() {
            defer wg.Done()
            fmt.Printf("goroutine %d\n", i)
        }()
    }
    wg.Wait()
}

Pułapka przechwytywania zmiennej pętli

Bez przechwycenia zmiennej pętli wszystkie gorutyny mogą zobaczyć tę samą wartość (końcową) — jest to klasyczny błąd współbieżności w Go:

package main
import ("fmt"; "sync")

func main() {
    var wg sync.WaitGroup
    for i := 0; i < 3; i++ {
        wg.Add(1)
        go func(n int) {  // pass i as argument — safe
            defer wg.Done()
            fmt.Println(n)  // prints 0, 1, 2 in some order
        }(i)
    }
    wg.Wait()
}

Gorutyny a wątki

Dlaczego gorutyny są preferowane zamiast wątków systemu operacyjnego:

  • Początkowy stos ma 2 KB, a wątki systemu operacyjnego około 1 MB
  • Ich utworzenie trwa mikrosekundy zamiast milisekund
  • Środowisko uruchomieniowe Go przeplata gorutyny na wątkach systemu operacyjnego określonych przez GOMAXPROCS
  • Przełączanie gorutyn odbywa się kooperacyjnie — bez udziału jądra
  • Go zajmuje się planowaniem, więc można skupić się na logice programu

GOMAXPROCS

runtime.GOMAXPROCS określa, ile wątków systemu operacyjnego może równolegle wykonywać gorutyny (domyślnie jest to liczba procesorów):

package main
import ("fmt"; "runtime")

func main() {
    // Default: number of available CPU cores
    fmt.Println("CPUs:", runtime.NumCPU())
    fmt.Println("GOMAXPROCS:", runtime.GOMAXPROCS(0)) // 0 = query without changing

    // Set to 1 for debugging race conditions:
    // runtime.GOMAXPROCS(1)

    fmt.Println("Goroutines:", runtime.NumGoroutine())
}

Wycieki gorutyn

Do wycieku gorutyny dochodzi, gdy gorutyna zostaje uruchomiona, ale nigdy się nie kończy. Typowe przyczyny to zablokowany odbiór z kanału, zablokowany mutex lub brak anulowania:

package main
import ("fmt"; "time"; "runtime")

func leaky() {
    ch := make(chan int)  // nobody sends to ch
    go func() {
        v := <-ch  // blocks forever — goroutine leaked!
        fmt.Println(v)
    }()
}

func main() {
    leaky()
    time.Sleep(10 * time.Millisecond)
    fmt.Println("goroutines:", runtime.NumGoroutine()) // > 1
}

Dobre praktyki dotyczące gorutyn

Wskazówki dotyczące gorutyn:

  • Zawsze należy wiedzieć, w jaki sposób gorutyna się zakończy
  • Do synchronizacji należy używać WaitGroup lub kanałów, a nie funkcji sleep
  • Zmienne pętli należy przekazywać jako argumenty funkcji, a nie za pomocą domknięcia
  • Gorutyny należy anulować za pomocą context, zamiast pozostawiać je uruchomione
  • Należy używać detektora wyścigów danych: go run -race main.go

Szybki test

Jaki jest prawidłowy sposób uniknięcia błędu przechwytywania zmiennej pętli w gorutynach?

Podsumowanie: uruchamianie gorutyn

Podsumowanie:

  • Uruchamianie za pomocą go fn() — lekkie i tanie
  • Do oczekiwania należy używać sync.WaitGroup: Add(1), defer Done(), Wait()
  • Zmienne pętli należy przechwytywać jako argument lub przez ponowną deklarację
  • Zawsze należy wiedzieć, jak każda gorutyna się kończy — zapobiega to wyciekom
  • Flagi -race należy używać do wykrywania wyścigów danych

Często zadawane pytania

Czy lekcja „Uruchamianie goroutines” jest bezpłatna?

Tak — pełny tekst „Uruchamianie goroutines” jest dostępny za darmo tutaj w sieci. Aby ćwiczyć ją interaktywnie (wbudowany edytor kodu i tutor AI dostępny 24/7) i odblokować resztę kursu Go Academy, przejdź na CoddyKit PRO. Kurs Go Academy zawiera 4 lekcji w sumie.

Co nauczysz się w „Uruchamianie goroutines”?

Słowo kluczowe go, cykl życia goroutines i WaitGroups Ćwiczysz Go Academy z praktycznym kodem, który uruchamiasz bezpośrednio w przeglądarce, a tutor AI dostępny 24/7 odpowiada na Twoje pytania podczas pracy nad lekcją.

Czy potrzebuję doświadczenia, aby zacząć Go Academy?

Nie wymagamy żadnego doświadczenia. Go Academy w CoddyKit jest strukturyzowany dla początkujących i zaawansowanych użytkowników, więc możesz zacząć tutaj lub od początku i uczyć się w swoim tempie. To lekcja 1 z 4.

Ile czasu zajmuje lekcja „Uruchamianie goroutines”?

Większość lekcji CoddyKit trwa około 5–10 minut. Każda lekcja to mały, interaktywny krok, dzięki czemu robisz systematyczne postępy i zawsze wracasz dokładnie do tego samego miejsca — na webie i w aplikacji.

Czy mogę pisać i uruchamiać kod w tej lekcji Go Academy?

Tak. Każda lekcja Go Academy zawiera wbudowany edytor kodu, więc piszesz i uruchamiasz prawdziwy kod bezpośrednio w przeglądarce i od razu otrzymujesz sprzężenie zwrotne od AI — bez konfiguracji na komputerze.

Wszystkie lekcje w tym kursie

  1. Uruchamianie goroutines
  2. Kanały niebuforowane
  3. Kanały buforowane
  4. Kierunek kanałów i wzorce potoków
← Powrót do Go Academy