0Pricing
Go Academy · درس

تشغيل Goroutines

كلمة go ودورة حياة goroutine وWaitGroups

تشغيل Goroutines درس مجاني في Go Academy على CoddyKit. هذا هو الدرس 1 من أصل 4. يمكنك قراءة الدرس كاملاً أدناه مجاناً — ثم تمرن عليه مباشرة في المتصفح باستخدام محرر أكواد مدمج ومدرس ذكاء اصطناعي متاح 24/7. هذا الدرس جزء من مسار التعلم في Go Academy، وتقدمك يتزامن عبر الويب وتطبيق CoddyKit. تتضمن دورة Go Academy 4 دروس في المجموع.

ما هي الغوروتين؟

الغوروتين goroutine هي دالة خفيفة الوزن تُنفَّذ بالتزامن وتديرها بيئة تشغيل Go. والغوروتينات أقل تكلفة بكثير من خيوط نظام التشغيل، لذا يمكنكم تشغيل الآلاف منها:

  • ابدؤوا باستخدام الكلمة المفتاحية go
  • حجم المكدس الابتدائي نحو 2 كيلوبايت (ويزداد ديناميكيًا)
  • تُجدولها بيئة تشغيل Go، وليس نظام التشغيل
  • تتواصل عبر القنوات، لا عبر الذاكرة المشتركة

الكلمة المفتاحية go

أضفوا go قبل أي استدعاء دالة لإطلاقها كغوروتين:

package main
import ("fmt"; "time")

func greet(name string) {
    fmt.Printf("Hello, %s!\n", name)
}

func main() {
    go greet("Alice")   // runs concurrently
    go greet("Bob")     // runs concurrently
    time.Sleep(100 * time.Millisecond) // wait for goroutines
    fmt.Println("done")
}

دورة حياة الغوروتين

تبدأ الغوروتين عند تنفيذ عبارة go وتنتهي عند عودة دالتها. إذا عادت main، تُنهى جميع الغوروتينات:

package main
import ("fmt"; "time")

func worker(id int) {
    fmt.Printf("Worker %d starting\n", id)
    time.Sleep(time.Duration(id) * 50 * time.Millisecond)
    fmt.Printf("Worker %d done\n", id)
}

func main() {
    for i := 1; i <= 3; i++ {
        go worker(i)
    }
    time.Sleep(300 * time.Millisecond) // naive wait
}

sync.WaitGroup للتنسيق

استخدموا sync.WaitGroup بدلًا من النوم للانتظار حتى انتهاء الغوروتينات:

package main
import ("fmt"; "sync")

func worker(id int, wg *sync.WaitGroup) {
    defer wg.Done()  // signal completion
    fmt.Printf("Worker %d working\n", id)
}

func main() {
    var wg sync.WaitGroup
    for i := 1; i <= 5; i++ {
        wg.Add(1)           // register one goroutine
        go worker(i, &wg)
    }
    wg.Wait()               // block until all Done()
    fmt.Println("all workers finished")
}

الغوروتينات المجهولة

أطلقوا دالة مجهولة مباشرةً كغوروتين — وهذا مفيد للمهام المتزامنة المضمّنة:

package main
import ("fmt"; "sync")

func main() {
    var wg sync.WaitGroup
    for i := 0; i < 3; i++ {
        i := i  // capture loop variable
        wg.Add(1)
        go func() {
            defer wg.Done()
            fmt.Printf("goroutine %d\n", i)
        }()
    }
    wg.Wait()
}

مشكلة التقاط متغير الحلقة

من دون التقاط متغير الحلقة، قد ترى جميع الغوروتينات القيمة نفسها (النهائية) — وهذا خطأ شائع في التزامن باستخدام Go:

package main
import ("fmt"; "sync")

func main() {
    var wg sync.WaitGroup
    for i := 0; i < 3; i++ {
        wg.Add(1)
        go func(n int) {  // pass i as argument — safe
            defer wg.Done()
            fmt.Println(n)  // prints 0, 1, 2 in some order
        }(i)
    }
    wg.Wait()
}

الغوروتينات مقابل الخيوط

لماذا يُفضَّل استخدام الغوروتينات بدلًا من خيوط نظام التشغيل:

  • مكدس ابتدائي بحجم 2 كيلوبايت مقابل نحو 1 ميغابايت لخيوط نظام التشغيل
  • يستغرق إنشاؤها ميكروثوانٍ مقابل ميليثوانٍ
  • توزّع بيئة تشغيل Go الغوروتينات على خيوط نظام التشغيل التي يحددها GOMAXPROCS
  • تبديل الغوروتينات تعاوني — ولا يتطلب تدخل النواة
  • تتولى Go الجدولة، بينما تركزون على المنطق

GOMAXPROCS

يتحكم runtime.GOMAXPROCS في عدد خيوط نظام التشغيل التي تشغّل الغوروتينات بالتوازي (ويكون افتراضيًا مساويًا لعدد وحدات المعالجة المركزية):

package main
import ("fmt"; "runtime")

func main() {
    // Default: number of available CPU cores
    fmt.Println("CPUs:", runtime.NumCPU())
    fmt.Println("GOMAXPROCS:", runtime.GOMAXPROCS(0)) // 0 = query without changing

    // Set to 1 for debugging race conditions:
    // runtime.GOMAXPROCS(1)

    fmt.Println("Goroutines:", runtime.NumGoroutine())
}

تسرّب الغوروتينات

يحدث تسرّب الغوروتين عند بدء غوروتين دون أن تنتهي أبدًا. ومن أسبابه الشائعة: انتظار استقبال محظور على قناة، أو كائن mutex محظور، أو عدم وجود إلغاء:

package main
import ("fmt"; "time"; "runtime")

func leaky() {
    ch := make(chan int)  // nobody sends to ch
    go func() {
        v := <-ch  // blocks forever — goroutine leaked!
        fmt.Println(v)
    }()
}

func main() {
    leaky()
    time.Sleep(10 * time.Millisecond)
    fmt.Println("goroutines:", runtime.NumGoroutine()) // > 1
}

أفضل ممارسات الغوروتينات

إرشادات الغوروتينات:

  • اعرفوا دائمًا كيف ستنتهي الغوروتين
  • استخدموا WaitGroup أو القنوات للمزامنة، لا النوم
  • مرّروا متغيرات الحلقة كوسيطات للدوال، لا عبر الإغلاق
  • ألغوا الغوروتينات باستخدام context، ولا تتركوها قيد التشغيل
  • استخدموا كاشف التنافس: go run -race main.go

تحقق سريع

ما الطريقة الصحيحة لتجنب خطأ التقاط متغير الحلقة في الغوروتينات؟

مراجعة: إطلاق الغوروتينات

الملخص:

  • أطلقوها باستخدام go fn() — فهي خفيفة ومنخفضة التكلفة
  • استخدموا sync.WaitGroup للانتظار: Add(1) وdefer Done() وWait()
  • التقطوا متغيرات الحلقة باستخدام وسيط أو إعادة التصريح
  • اعرفوا دائمًا كيف تنتهي كل غوروتين — لمنع التسرب
  • استخدموا الخيار -race لاكتشاف حالات التنافس على البيانات

الأسئلة الشائعة

هل درس «تشغيل Goroutines» مجاني؟

نعم — نص درس «تشغيل Goroutines» كامل متاح مجاناً هنا على الويب. لتمرينه بشكل تفاعلي (محرر أكواد مدمج ومدرس ذكاء اصطناعي متاح 24/7) وفتح باقي دورة Go Academy، انتقل إلى CoddyKit PRO. تتضمن دورة Go Academy 4 دروس في المجموع.

ماذا ستتعلم في «تشغيل Goroutines»؟

كلمة go ودورة حياة goroutine وWaitGroups تتمرن على Go Academy مع أكواد عملية تشغلها مباشرة في المتصفح، ومدرس ذكاء اصطناعي متاح 24/7 يجيب على أسئلتك أثناء عملك.

هل أحتاج إلى خبرة سابقة لأبدأ Go Academy؟

لا تُشترط خبرة سابقة. Go Academy على CoddyKit منظم للمبتدئين حتى المتقدمين، لذا يمكنك البدء من هنا أو من البداية والتقدم بسرعتك الخاصة. هذا هو الدرس 1 من أصل 4.

كم من الوقت يستغرق درس «تشغيل Goroutines»؟

معظم دروس CoddyKit تستغرق حوالي 5–10 دقائق. كل منها موجز وتفاعلي، لذا تحرز تقدماً مستمراً وتستأنف من حيث توقفت عبر الويب والتطبيق.

هل يمكنني كتابة وتشغيل أكواد في درس Go Academy هذا؟

نعم. كل درس في Go Academy يتضمن محرر أكواد مدمج، لذا تكتب وتشغل أكواداً حقيقية مباشرة في متصفحك وتحصل على تعليقات فورية من الذكاء الاصطناعي — بدون إعداد محلي.

جميع الدروس في هذه الدورة

  1. تشغيل Goroutines
  2. القنوات غير المخزَّنة
  3. القنوات المخزَّنة
  4. اتجاه القنوات وأنماط خطوط الأنابيب
← العودة إلى Go Academy