Middle+
Povězte o plánování goroutines v Go.
sobes.tech AI
Odpověď od AI
Plánovač gorutin v jazyce Go používá model M:N, kde M gorutin je mapováno na N vlákna OS. Efektivně přepíná gorutiny mezi vlákny, implementujíc předčasné přerušení (preemption points) s body zastavení.
Hlavní komponenty modelu GPM:
- G (Goroutine): Abstrakce vykonávající jednotky kódu, lehký vlákno řízené plánovačem Go.
- P (Processor): Logický procesor, představující kontext lokální fronty gorutin a zdrojů, jako jsou mutexy a plánovač. Počet P je standardně určen počtem logických jader procesoru, ale může být změněn přes
GOMAXPROCS. - M (Machine/Thread): Vlákno operačního systému, které vykonává kód. M je spojeno s P a vykonává gorutiny z lokální fronty P nebo globální fronty.
Princip fungování:
- Nová gorutina je vytvořena a umístěna do lokální fronty dostupného P.
- M, spojené s P, vezme gorutinu z lokální fronty a vykoná ji.
- Pokud je lokální fronta prázdná, M se pokusí ukrást gorutiny od jiných P.
- Pokud je P zablokováno (například při volání systémových funkcí), spojení s ním M odpojí a spojí se s jiným M. Zablokované M může být znovu použito, když systémové volání skončí.
- Pokud je gorutina zablokována na kanálu nebo mutexu, je zařazena do fronty čekání a plánovač vybere jinou gorutinu k vykonání na stejném M.
- Plánovač provádí periodické kontroly pro předčasné přerušení dlouho běžících gorutin, umožňující jiným gorutinám získat čas na vykonání.
Body předčasného přerušení (preemption points) vznikají na určitých místech:
- Volání funkcí/metod.
- Smyčky obsahující volání funkcí.
- Alokace paměti.
- Synchronizační primitivy (kanály, mutexy).
Příklad plánování:
package main
import (
"fmt"
"runtime"
"time"
)
func worker(id int) {
fmt.Printf("Gorutina %d začala práci\n", id)
time.Sleep(time.Second) // Simulace práce
fmt.Printf("Gorutina %d skončila práci\n", id)
}
func main() {
runtime.GOMAXPROCS(2) // Nastavení počtu logických procesorů
for i := 1; i <= 5; i++ {
go worker(i) // Vytvoření gorutin
}
time.Sleep(3 * time.Second) // Čekání na dokončení gorutin
fmt.Println("Hlavní gorutina ukončena")
}
V tomto příkladu jsou 5 gorutin naplánováno na 2 logické procesory. Plánovač Go bude rozdělovat tyto gorutiny mezi dostupné vlákna OS, využívajíc lokální a případně globální fronty, stejně jako mechanismus "krádeže" práce (work stealing).
Výhody tohoto přístupu:
- Škálovatelnost: Efektivní využití vícejádrových systémů.
- Nízké režijní náklady: Lehká gorutina ve srovnání s vlákny OS.
- Jednoduchost použití: Integrované plánování v jazyce činí paralelní programování přístupnější.