Sobes.tech
Middle+

Ispričajte o planiranju goroutine u Go.

sobes.tech АИ

Одговор од АИ

Planer gorutina u Go koristi model M:N, gde je M gorutina mapirano na N niti OS-a. Efikasno prebacuje gorutine između niti, implementirajući neprimenjivu multitaskingu sa tačkama zaustavljanja (preemption points).

Glavne komponente GPM modela:

  • G (Goroutine): Apstrakcija izvršne jedinice koda, lagani tok, upravljan od strane planera Go.
  • P (Processor): Logički procesor, predstavljajući kontekst lokalne reda gorutina i resursa kao što su muteksi i planer. Broj P je podrazumevano određen brojem logičkih jezgara procesora, ali može biti promenjen putem GOMAXPROCS.
  • M (Machine/Thread): Tok operativnog sistema koji izvršava kod. M je povezan sa P i izvršava gorutine iz lokalne ili globalne reda.

Princip rada:

  1. Nova gorutina se kreira i smešta u lokalnu red dostupnog P.
  2. M, povezano sa P, uzima gorutinu iz lokalne reda i izvršava je.
  3. Ako je lokalna red prazan, M pokušava da ukrade gorutine od drugih P.
  4. Ako P blokira (npr. prilikom sistemskog poziva), povezani M se odvoji, a drugi M se povezuje sa tim P. Blokirani M može biti ponovo korišćen kada sistemski poziv završi.
  5. Ako je gorutina blokirana na kanalu ili muteksu, ona se stavlja u red čekanja, a planer bira drugu gorutinu za izvršenje na istom M.
  6. Planer vrši periodične provere za preemptivno prekidanje dugotrajnih gorutina, omogućavajući drugim gorutinama da dobiju vreme za izvršenje.

Tačke preemptivnog prekida (preemption points) javljaju se na određenim mestima:

  • Pozivi funkcija/metoda.
  • Petlje koje sadrže pozive funkcija.
  • Alokacija memorije.
  • Sinhronizacioni primitivi (kanali, muteksi).

Primer planiranja:

package main

import (
	"fmt"
	"runtime"
	"time"
)

func worker(id int) {
	fmt.Printf("Gorutina %d je počela rad\n", id)
	time.Sleep(time.Second) // Simulacija rada
	fmt.Printf("Gorutina %d je završila rad\n", id)
}

func main() {
	runtime.GOMAXPROCS(2) // Podesavanje broja logičkih procesora

	for i := 1; i <= 5; i++ {
		go worker(i) // Kreiranje gorutina
	}

	time.Sleep(3 * time.Second) // Čekanje završetka gorutina
	fmt.Println("Glavna gorutina je završena")
}

U ovom primeru, 5 gorutina je planirano na 2 logička procesora. Planer Go će rasporediti ove gorutine između dostupnih niti OS-a koristeći lokalne i moguće globalne redove, kao i mehanizam "krađe" rada (work stealing).

Prednosti ovog pristupa:

  • Skalabilnost: Efikasno korišćenje višejadarskih sistema.
  • Niski troškovi: Laki gorutini u poređenju sa niti OS-a.
  • Jednostavnost korišćenja: Ugrađeno planiranje u jeziku čini paralelno programiranje pristupačnijim.