דילוג לתוכן המרכזי
מודול 7 · שיעור 1 מתוך 531/50 בקורס~12 min
שיעורי מודול (1/5)

Goroutines: מקביליות קלת משקל

goroutine היא יחידה של ביצוע במקביל המנוהלת על ידי ה-Go זמן ריצה. אתה מפעיל אחד עם מילת המפתח go לפני פונקציה להתקשר:

Go
go greet("Anna")         // chiamata a funzione esistente
go func() {              // funzione anonima
    fmt.Println("hi")
}()

ההצהרה go חוזרת מיד: הגורוטין מתחיל ב במקביל והמתקשר ממשיך.

למה הם "קלי משקל"

  • מחסנית ראשונית ~2KB (גדל באופן דינמי, עד מאות MB במידת הצורך).
  • משולבת על מספר קטן של שרשורי מערכת הפעלה לפי זמן הריצה (GOMAXPROCS).
  • אלפי/מיליוני גורוטינים הם דבר שבשגרה; עם שרשורי מערכת הפעלה הם יהיו בלתי אפשריים.

מבחינה קונספטואלית זה "אש ושכח במקביל", אבל עם כל כלים אידיומטיים לתיאום (ערוצים, sync.WaitGroup, context).

ראשי לא מחכה

Go
func main() {
    go func() { fmt.Println("ciao dalla goroutine") }()
    // main esce subito: niente garanzia che la goroutine completi
}

כאשר main חוזר, התהליך מסתיים: גורוטינים לא מקבלים כדי "לסיים את עבודתם", הם פשוט נהרגים יחד עם תהליך. נדרש סנכרון מפורש.

סנכרון: תצוגה מקדימה

שלושת הכלים שתראו בשיעורים הבאים:

Go
// 1) Channel: la goroutine "segnala" via canale
done := make(chan struct{})
go func() {
    work()
    done <- struct{}{}
}()
<-done   // attendi

// 2) sync.WaitGroup: N goroutine
var wg sync.WaitGroup
wg.Add(1)
go func() { defer wg.Done(); work() }()
wg.Wait()

// 3) context: cancellazione/timeout propagati

באג הסגירה ה"קלאסי".

עד Go 1.21 זה היה תקלה תכופה:

Go
for i := 0; i < 3; i++ {
    go func() { fmt.Println(i) }()  // stampa "3 3 3" su versioni vecchie
}

החל מ-עבור 1.22 המשתנה for נוצר לאחרונה בכל אחד מהם איטרציה, כך שהבאג תוקן כברירת מחדל. בבסיסי קוד ישנים יותר תעשה זאת עדיין רואים את דפוס התיקון:

Go
for i := 0; i < 3; i++ {
    i := i           // shadow esplicito
    go func() { fmt.Println(i) }()
}
// oppure passa come argomento:
for i := 0; i < 3; i++ {
    go func(n int) { fmt.Println(n) }(i)
}

Goroutine != שרשור מערכת ההפעלה

היבטGoroutineשרשור מערכת הפעלה
מחסנית ראשונית~2 KB1–8 מגה-בייט (מוקצה בהתחלה)
יצירהננו-שניותמיקרו שניות
תזמוןעבור זמן ריצה (שיתופיות)קרנל (מנע)
ספירה מעשית100K+כמה אלפים

שרשור מערכת הפעלה בודד יכול לארח גורוטיינים רבים. זמן הריצה זז גורוטינים על פני חוטים בעת הצורך.

נסה את זה

פעילות גופנית#go.m7.l1.e1
ניסיונות: 0טוען...

הפעל את פונקציית הברכה כגורוטינה והמתן 100 אלפיות השנייה עם הזמן. שינה לפני היציאה הראשית.

טוען עורך...
הצג רמז

'גו' לפני קריאת פונקציה מפעיל את הגורוטין.

הפתרון זמין לאחר 3 ניסיונות

פעילות גופנית#go.m7.l1.e2
ניסיונות: 0טוען...

הפעל פונקציה אנונימית כגורוטינה שמדפיסה 'היי'.

טוען עורך...
הצג רמז

פונקציה אנונימית נקראת עם `()` עוקב: `go func(){...}()`.

הפתרון זמין לאחר 3 ניסיונות

Quiz#go.m7.l1.e3
מוכן

מה קורה אם 'ראשי' יוצא לפני שגורוטינה מסתיימת?

Go
func main() {
  go work()
  // main ritorna immediatamente
}
אפשרויות תשובה

לְסַכֵּם

  • go f() משגר את f() במקביל; זה חוזר מיד.
  • Goroutine = ~2 KB ראשוני, מרובב על כמה שרשורי מערכת הפעלה.
  • main לא ממתין: אתה צריך סנכרון (ערוץ/קבוצת המתנה/הקשר).
  • time.Sleep הוא דידקטי בלבד, לעולם לא לסנכרון בהפקה.
  • מ-Go 1.22 המשתנה for הוא "טרי" בכל איטרציה (לא עוד באג "3 3 3").