Gorutyna to lekki wątek wykonawczy, zarządzany przez środowisko uruchomieniowe Go. Aby uruchomić nową gorutynę, używa się słowa kluczowego go przed wywołaniem funkcji. Pod spodem tworzona jest struktura opisująca stos i stan zadania, która zostaje dodana do kolejki planera gorutyn.
W przeciwieństwie do wątków OS, gorutyna ma znacznie mniejszy początkowy stos (zazwyczaj 2 KB), a stos automatycznie się rozszerza w razie potrzeby. Planer Go samodzielnie przydziela je do dostępnych wątków systemu operacyjnego (model M:N).
Główne różnice w porównaniu do wątków (threads):
package main import ( "fmt" "time" ) func worker(id int, jobs <-chan int, results chan<- int) { for j := range jobs { fmt.Printf("worker %d rozpoczął zadanie %d ", id, j) time.Sleep(time.Second) fmt.Printf("worker %d zakończył zadanie %d ", id, j) results <- j * 2 } } func main() { jobs := make(chan int, 5) results := make(chan int, 5) for w := 1; w <= 3; w++ { go worker(w, jobs, results) } for j := 1; j <= 5; j++ { jobs <- j } close(jobs) for a := 1; a <= 5; a++ { <-results } }
Czy gorutyny Go mogą być wykonywane równolegle na kilku rdzeniach?
Często spotyka się błędną odpowiedź: "Nie, ponieważ Go używa zielonych wątków". W rzeczywistości, za pomocą zmiennej środowiskowej lub wywołania runtime.GOMAXPROCS(n), Go może równolegle wykonywać gorutyny na wszystkich dostępnych rdzeniach procesora.
import "runtime" func main() { runtime.GOMAXPROCS(4) // Pozwala na użycie 4 rdzeni ... }
Historia
W projekcie backendowym usługi na Go zrealizowano pulę pracowników przez gorutyny, ale programiści zapomnieli ograniczyć liczbę jednocześnie działających gorutyn. W rezultacie, przy zwiększonym obciążeniu, aplikacja uruchamiała tysiące gorutyn, co doprowadziło do wyczerpania pamięci i awarii usługi. Problem rozwiązano wprowadzając limit aktywnych gorutyn (np. przy pomocy semafora lub puli pracowników).
Historia
Jeden z pracowników błędnie zsynchronizował dane między gorutynami, używając zwykłych zmiennych globalnych bez mutexów lub kanałów. Spowodowało to wyścig danych (race condition), przez co okresowo pojawiały się błędy przy przetwarzaniu płatności. Problem został wykryty dopiero po uruchomieniu w produkcji.
Historia
W serwisie analizy danych pominięto moment przekazania nil-kanałów w select: po zamknięciu kanału select nadal czekał na dane, przez co część gorutyn „zawiesiła się”. Naprawiono poprzez przypisanie nil do zamkniętego kanału oraz właściwe przetwarzanie select.