دليل شامل لـ sync/errgroup في Go مع أمثلة عملية

مدرب بايثون أونلاين للمبتدئين

تعلم Python بسهولة دون إرهاق نظري. حل مهام عملية مع التحقق التلقائي واكتب الكود مباشرة في المتصفح.

ابدأ الدورة

دليل شامل لـ sync/errgroup في Go مع أمثلة عملية

1. ما هي sync/errgroup ولماذا تحتاجها؟

مكتبة sync/errgroup هي جزء من الحزمة الرسمية الموسعة golang.org/x/sync، وتوفر طريقة قوية وأنيقة لإدارة الغوروتينات المتوازية مع معالجة الأخطاء. في مكتبة Go القياسية، يوجد حزمة sync مع WaitGroup، لكنها لا تستطيع جمع الأخطاء من الغوروتينات. errgroup تحل هذه المشكلة: تقوم بتشغيل عدة غوروتينات، وإذا أرجعت إحداها خطأً، تقوم المجموعة بإلغاء السياق فورًا (أو بعد اكتمال الجميع) وتسمح للغوروتينات الأخرى بالإنهاء بشكل صحيح.

لماذا تحتاج هذا؟ في التطبيقات الواقعية، غالبًا ما تحتاج لتنفيذ عدة مهام مستقلة بالتوازي: تحميل ملفات، معالجة بيانات، إجراء استعلامات API. إذا فشلت مهمة واحدة بخطأ، فلا فائدة من الاستمرار في الباقي - تحتاج للتوقف بسرعة وإرجاع الخطأ للمستخدم. errgroup تقوم بذلك تلقائيًا: تمرر سياقًا، وعند أول خطأ يتم إلغاء السياق، ويمكن لجميع الغوروتينات التي تستمع لهذا السياق أن تنهي عملها مبكرًا.

هذا مفيد بشكل خاص في الخدمات المصغرة، خوادم الويب، والأدوات سطر الأوامر حيث سرعة الاستجابة للأخطاء مهمة. على عكس الإدارة اليدوية باستخدام القنوات و select، يوفر errgroup واجهة برمجية نظيفة وتصريحية يصعب استخدامها بشكل خاطئ.

2. طريقة التثبيت

sync/errgroup ليست جزءًا من المكتبة القياسية لـ Go، لكنها جزء من الوحدة الفرعية golang.org/x/sync. يتم التثبيت بأمر واحد:

go get golang.org/x/sync/errgroup

بعد ذلك، يمكنك استيراد الحزمة في الكود الخاص بك:

import "golang.org/x/sync/errgroup"

تأكد من أن لديك Go إصدار 1.13 أو أعلى (يُوصى بـ 1.18+ لدعم الـ generics، على الرغم من أن errgroup لا تستخدمها). إذا كنت تستخدم الوحدات (go.mod)، فإن الأمر go get سيقوم تلقائيًا بتحديث ملف go.sum.

3. بداية سريعة - مثال عملي بسيط

فيما يلي مثال بسيط يقوم بتشغيل ثلاث غوروتينات، كل منها ترجع خطأً إذا كان الرقم المُمرر سالبًا. إذا أرجعت إحدى الغوروتينات خطأً، فإن errgroup.Wait() سترجعه.

package main

import (
    "context"
    "fmt"
    "golang.org/x/sync/errgroup"
)

func main() {
    g, ctx := errgroup.WithContext(context.Background())

    numbers := []int{1, -2, 3}
    for _, n := range numbers {
        n := n // التقاط المتغير
        g.Go(func() error {
            select {
            case <-ctx.Done():
                return ctx.Err()
            default:
            }
            if n < 0 {
                return fmt.Errorf("رقم سالب: %d", n)
            }
            fmt.Printf("تمت معالجة %d\n", n)
            return nil
        })
    }

    if err := g.Wait(); err != nil {
        fmt.Printf("خطأ: %v\n", err)
    } else {
        fmt.Println("تم إكمال جميع المهام بنجاح")
    }
}

المخرجات: تمت معالجة 1، تمت معالجة 3، خطأ: رقم سالب: -2. لاحظ أن الغوروتين التي تحتوي على الرقم 3 ربما لم يتم تنفيذها إذا تم إلغاء السياق قبل تشغيلها - وهذا يوضح آلية الإيقاف المبكر.

4. الدوال والطرق الأساسية

فيما يلي جميع العناصر الأساسية لواجهة API لحزمة errgroup. كل طريقة مصحوبة بالتوقيع والوصف ومثال عملي.

4.1. WithContext

التوقيع: func Wi

توصيات