ProgramlamaBackend geliştiricisi

Go'da closure'lar (kapalı fonksiyonlar) nasıl uygulanır, döngüler içinde goroutine'ler kullanırken hangi gizli tuzaklar vardır ve tipik hatalardan nasıl kaçınılır?

Hintsage yapay zeka asistanı ile mülakatları geçin

Cevap

Go'da closure'lar (kapalı fonksiyonlar), bulundukları kapsama alanındaki değişkenleri "kaplayan" (yakalanan) fonksiyonlardır. En sık olarak arallik fonksiyonlar için, diğer fonksiyonların içinde oluşturulan kapanışlar kullanılır.

Closure'larla çalışırken en yaygın sorun, döngü değişkenlerinin goroutine içinde kullanılması sırasında beklenmedik davranıştır:

for i := 0; i < 3; i++ { go func() { fmt.Println(i) }() }

Her bir goroutine, aynı i değerini yazdırabilir çünkü değişken i döngüdür ve closure, değişkeni değil, her bir iterasyondaki değerini yakalar.

Doğru yol:

for i := 0; i < 3; i++ { go func(val int) { fmt.Println(val) }(i) }

Bu davranış, closure'ın değişkenin referansını (adresini) tutmasından kaynaklanır, kesilmiş değerini (by value) değil.

Yanıltıcı soru

Bir döngü içinde başlatılan birkaç goroutine, döngü değişkenini yakaladıklarında hangi değeri yazdıracaklar?

Cevap: Tüm goroutine'ler aynı değeri (genellikle son değeri) yazdırabilir çünkü güncel değişken değerini görürler ve goroutine'ler çalışmaya başladığında döngü zaten tamamlanmıştır. Bu durumdan kaçınmak için değişkenin, closure'a parametre olarak geçirilmesi gerekir.

Örnek:

for i := 0; i < 5; i++ { go func() { fmt.Println(i) }() } // büyük ihtimalle: 5 5 5 5 5 alırız

Konunun inceliklerini bilmemekten kaynaklanan gerçek hatalar örnekleri


Hikaye

Bir ürün analiz sisteminde, döngü içinde değişkeni yakalayan closure ile veriler paralel goroutine'lerde anonimleştirildi. Sonuç olarak, tüm paralel görevler aynı veri kümesini işledi - sonuçta istatistiklerde bozulma ve hatalı raporlama ortaya çıktı.

Hikaye

Bulut tabanlı bir Go entegrasyon hizmetinde, ekipler metrik toplamayı optimize etmek için anonim fonksiyonlar kullanarak döngüde başlatmaya karar verdiler - goroutine içinde harita indeksini yakaladılar, sonuç: bazı işleyiciler verileri kendi hizmetleri için değil, son işlenen indeks için topladı.

Hikaye

Bir kargo girişiminde, closure'ların sipariş koordinatlarını güncellerken hatalı kullanımı, kesitteki son siparişin koordinatlarının topluca güncellenmesine, o anki koordinatların yerine geçmesine neden oldu - anonim fonksiyon içinde kesite erişim nedeniyle yarış durumundan dolayı.