Modül dersleri (5/5)
`context.Context`: iptal ve son tarihler
context paketi yayılma için fiili standarttır
çağrı zinciri boyunca iptal, son tarihler ve kapsama bağlı değerler,
birden fazla goroutine karşı. Tüm standart "ağ oluşturma" paketleri
(net/http, database/sql, os/exec) context.Context'ü şu şekilde kabul edin:
onların ilk parametresi.
Arayüz
type Context interface {
Deadline() (deadline time.Time, ok bool)
Done() <-chan struct{}
Err() error
Value(key any) any
}Done(): içerik iptal edildiğinde kapatılan kanal.Err(): iptal nedeni (context.Canceledveyacontext.DeadlineExceeded).Deadline(): isteğe bağlı son tarih.Value(): kapsama bağlı değerlerin aranması (idareli kullanın).
Dört temel işlev
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-boundTüretilen tüm formlar bir cancel işlevi döndürür: her zaman onu çağırın
(ideal olarak defer ile) dahili kaynakları serbest bırakmak için
bağlamın süresi zaten doldu.
Zaman aşımı modeli
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 2 saniyeden uzun sürerse ctx.Done() kapatılır ve
işlevin işlemi iptal etmesi gerekir.
Bağlama saygı göstererek: Bitti() seçeneğini seçin
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
}
}
}Kural: İşlevinizin uzun süre engelleyebileceği her yerde, ctx.Done()'u işlemelidir. Aksi halde bağlam "açıktır" hiçbir şey.
Birinci parametre kuralı
func Fetch(ctx context.Context, url string) ([]byte, error) { ... }
// ^^^^^^^^^^^^^^^^^^^
// SEMPRE primo, mai dentro a una struct, mai opzionalectxHER ZAMAN ilk parametre olarakctxadlı.- Asla
Contextöğesini bir yapının alanı olarak koymayın (çok nadir istisnalar). - Asla
nil'yi geçmeyin: saplama olarakcontext.TODO()kullanın.
context.WithValue: idareli
type userKey struct{}
ctx := context.WithValue(ctx, userKey{}, currentUser)
// più sotto:
if u, ok := ctx.Value(userKey{}).(*User); ok { ... }Yönergeler:
- YALNIZCA istek kapsamlı veriler için (istek kimliği, izleme kimliği, kullanıcı kimliği).
- ASLA fonksiyon parametreleri için: bunları normal şekilde iletin.
- Çarpışmaları önlemek için dışa aktarılmayan özel türde anahtarlar.
Zincir boyunca yayılma
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, istemci olduğunda r.Context() otomatik olarak iptal edilir.
bağlantı kesildiğinde veya işleyici geri döndüğünde. Bunu herkese yayarak
aşağı yönlü aramalarda tüm işlem ağacı iptal edilir
kademeli: bağlantı kesildikten sonra iş israfı olmaz.
Deneyin
context.Background()'dan türetilmiş 1 saniyelik zaman aşımına sahip bir bağlam oluşturun ve defer ile cancel çağrısını yapmayı unutmayın.
İpucu göster
'context.WithTimeout(parent, d)', '(ctx, cancel)' değerini döndürür; her zaman ara iptal et.
3 denemeden sonra çözüm mevcut
Bağlamın iptal edilmesini beklemek için seçimde <-ctx.Done() öğesini kullanın.
İpucu göster
`ctx.Done()`, içerik iptal edildiğinde kapanan bir kanaldır.
3 denemeden sonra çözüm mevcut
Geleneksel olarak, ctx parametresi bir işlev imzasında nereye gider?
func Fetch(???, url string) ([]byte, error)Özet
context.Contextiptali, son tarihi ve kapsama bağlı değerleri yayar.- Kök olarak
Background()/TODO();WithCancel/WithTimeout/WithDeadlinetüretmek için. - Kaynakları serbest bırakmak için her zaman
defer cancel(). - "Uzun" işlevler
selectüzerindectx.Done()olmalıdır veya ctx'i standart paketlere geçirmelidir. - Kural:
ctxFIRST parametresi olarak, asla bir yapının içinde değil. WithValueyalnızca istek kapsamlı veriler için (istek kimliği, izleme kimliği).net/http'de, istemci bağlantısı kesildiğinder.Context()iptal edilir.