Sobes.tech
Middle+

Opowiedz o wzorcu zarządzania współbieżnością (GMP) w języku Go.

sobes.tech AI

Odpowiedź od AI

GMP to model planowania wykonywania goroutine w Go, gdzie:

  • G (Goroutine): Lekki wątek wykonawczy, abstrakcja nad wątkami systemowymi.
  • M (Machine): Wątek systemu operacyjnego. Może wykonywać kod jednej lub wielu goroutine.
  • P (Processor): Logiczny procesor, reprezentujący kontekst do wykonywania goroutine. Każdemu P przypisany jest M, a P zawiera lokalną kolejkę goroutine w stanie runnable. Liczba P domyślnie to $GOMAXPROCS (zwykle liczba rdzeni procesora).

Działanie:

  1. Harmonogram (część runtime Go) umieszcza nowe goroutine w globalnych lub lokalnych kolejach P.
  2. M, powiązany z P, pobiera goroutine z kolejki P i ją wykonuje.
  3. Gdy goroutine się blokuje (np. oczekując na I/O lub na mutexie):
    • M odłącza się od aktualnego P.
    • Harmonogram próbuje znaleźć inny M, aby zajął to P, lub tworzy nowy.
    • Zablokowana goroutine jest umieszczana w specjalnej kolejce.
    • Gdy blokada zostaje zdjęta, goroutine wraca do stanu runnable i trafia z powrotem do kolejki P.
  4. Gdy goroutine wyczerpuje swój kwant czasu lub jawnie oddaje kontrolę (rzadko), harmonogram może przełączyć M na inną goroutine w tym samym P.

Zalety:

  • Efektywne wykorzystanie wątków systemowych M.
  • Zmniejszenie kosztów przełączania kontekstu w porównaniu do natywnych wątków systemu operacyjnego.
  • Równoważenie obciążenia między P za pomocą mechanizmu "work stealing" (M może ukraść goroutine z kolejki innego P).

Przykład tworzenia goroutine:

// main.go
package main

import (
	"fmt"
	"time"
)

func worker(id int) {
	fmt.Printf("Pracownik %d zaczyna\n", id)
	time.Sleep(time.Second) // Ilustracja blokady/zajętości
	fmt.Printf("Pracownik %d kończy\n", id)
}

func main() {
	for i := 1; i <= 5; i++ {
		go worker(i) // Tworzymy nową goroutine
	}

	time.Sleep(time.Second * 2) // Czekamy na zakończenie goroutine
}