الانتقال إلى المحتوى الرئيسي
الوحدة 7 · الدرس 5 من 535/50 في الدورة~14 min
دروس الوحدة (5/5)

`السياق.السياق`: الإلغاء والمواعيد النهائية

الحزمة context هي المعيار الفعلي للنشر ** الإلغاء والمواعيد النهائية والقيم المرتبطة بالنطاق ** على طول سلسلة الاتصال، عبر goroutines متعددة. جميع حزم "الشبكات" القياسية (net/http، database/sql، os/exec) قبول context.Context كـ المعلمة الأولى لهم

الواجهة

Go
type Context interface {
    Deadline() (deadline time.Time, ok bool)
    Done() <-chan struct{}
    Err() error
    Value(key any) any
}
  • Done(): القناة التي يتم إغلاقها عند إلغاء السياق.
  • Err(): سبب الإلغاء (context.Canceled أو context.DeadlineExceeded).
  • Deadline(): موعد نهائي اختياري.
  • Value(): بحث عن القيم المرتبطة بالنطاق (استخدمه باعتدال).

الوظائف الأربع الأساسية

Go
ctx := context.Background()              // radice: usalo in main, init, test
ctx := context.TODO()                    // "non so ancora": stub esplicito

ctx, cancel := context.WithCancel(parent)               // cancel manuale
ctx, cancel := context.WithTimeout(parent, d)           // scadenza relativa
ctx, cancel := context.WithDeadline(parent, t)          // scadenza assoluta

ctx := context.WithValue(parent, key, value)            // valore scope-bound

تُرجع كافة النماذج المشتقة دالة cancel: اتصل بها دائمًا (مثاليًا مع defer) لتحرير الموارد الداخلية، حتى لو كان لقد انتهت صلاحية السياق بالفعل.

نمط المهلة

Go
func fetchUser(id string) (*User, error) {
    ctx, cancel := context.WithTimeout(context.Background(), 2*time.Second)
    defer cancel()

    return queryUser(ctx, id)   // queryUser deve rispettare ctx
}

إذا استغرق queryUser أكثر من ثانيتين، فسيتم إغلاق ctx.Done() و يجب أن تقوم الوظيفة بإحباط العملية.

احترام السياق: حدد على تم ()

Go
func slowWork(ctx context.Context) error {
    for {
        select {
        case <-ctx.Done():
            return ctx.Err()      // canceled o deadline exceeded
        case <-time.After(100 * time.Millisecond):
            // un tick di lavoro
        }
    }
}

القاعدة: في أي مكان قد يتم حظر وظيفتك فيه لفترة طويلة، فإنه ** يجب التعامل مع ctx.Done()**. وإلا فسيتم "تشغيل" السياق لـ لا شيء.

اتفاقية المعلمة الأولى

Go
func Fetch(ctx context.Context, url string) ([]byte, error) { ... }
//        ^^^^^^^^^^^^^^^^^^^
// SEMPRE primo, mai dentro a una struct, mai opzionale
  • ctx دائمًا كمعلمة أولى، تسمى ctx.
  • لا تضع أبدًا Context كحقل للبنية (استثناءات نادرة جدًا).
  • لا تمر أبدًا nil: استخدم context.TODO() ككعب روتين.

context.WithValue: باعتدال

Go
type userKey struct{}

ctx := context.WithValue(ctx, userKey{}, currentUser)
// più sotto:
if u, ok := ctx.Value(userKey{}).(*User); ok { ... }

المبادئ التوجيهية:

  • فقط للبيانات ** على مستوى الطلب ** (معرف الطلب، ومعرف التتبع، وهوية المستخدم).
  • أبدًا بالنسبة لمعلمات الوظيفة: قم بتمريرها بشكل طبيعي.
  • مفاتيح من النوع ** المخصص غير المُصدَّر ** لتجنب الاصطدامات.

الانتشار على طول السلسلة

Go
func handleHTTP(w http.ResponseWriter, r *http.Request) {
    ctx := r.Context()   // context legato al ciclo di vita della richiesta
    user, err := fetchUser(ctx, r.URL.Query().Get("id"))
    if err != nil { ... }
    // ...
}

net/http يلغي تلقائيًا r.Context() عندما يقوم العميل قطع الاتصال أو عندما يعود المعالج. من خلال نشرها للجميع المكالمات النهائية، يتم إلغاء شجرة العمليات بأكملها تتالي: لا يوجد عمل ضائع بعد قطع الاتصال.

جربه

تمرين#go.m7.l5.e1
المحاولات: 0جارٍ التحميل…

قم بإنشاء سياق بمهلة ثانية واحدة مشتقة من context.Background() وتذكر استدعاء الإلغاء مع التأجيل.

جارٍ تحميل المحرر…
إظهار التلميح

`context.WithTimeout(parent, d)` يُرجع `(ctx, Cancel)`; اتصل دائمًا بالإلغاء.

الحل متاح بعد 3 من المحاولات

تمرين#go.m7.l5.e2
المحاولات: 0جارٍ التحميل…

استخدم <-ctx.Done() في التحديد لانتظار إلغاء السياق.

جارٍ تحميل المحرر…
إظهار التلميح

`ctx.Done()` هي قناة تُغلق عند إلغاء السياق.

الحل متاح بعد 3 من المحاولات

Quiz#go.m7.l5.e3
جاهز

حسب الاصطلاح، أين تذهب معلمة ctx في توقيع الوظيفة؟

Go
func Fetch(???, url string) ([]byte, error)
خيارات الإجابة

خلاصة

  • context.Context ينشر الإلغاء والموعد النهائي والقيم المرتبطة بالنطاق.
  • Background()/TODO() كجذر؛ WithCancel/WithTimeout/WithDeadline للاشتقاق.
  • defer cancel() دائمًا لتحرير الموارد.
  • يجب أن تكون الوظائف "الطويلة" select على ctx.Done() أو تمرر ctx إلى الحزم القياسية.
  • الاصطلاح: ctx كمعلمة FIRST، وليس داخل البنية أبدًا.
  • WithValue فقط للبيانات ذات نطاق الطلب (معرف الطلب، معرف التتبع).
  • في net/http، يتم إلغاء r.Context() عند قطع اتصال العميل.