ProgramlamaGo Geliştirici

Go'da time.Sleep ve time.After ile çalışmanın özelliğini açıklayın: fark ne, ne zaman ne uygulanmalı ve time.Sleep ile rekabetçi programlarda çalışırken hangi tuzaklar var?

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

Cevap.

Soru tarihçesi:

Go dili, zaman yönetimi için temel işlevler olan time.Sleep ve time.After ile time paketini ilk gününden itibaren sağlamıştır. Sistem uykusu (System.sleep) olan dillerin aksine, Go, kendi primitifleri aracılığıyla asenkron zamanlayıcıları uygular, bu çoklu iş parçacığı çalışması için önemlidir.

Sorun:

Geliştiriciler sıklıkla görevler arasında beklemeler uygulamak için time.Sleep'i yanlış kullanır, bu da rekabetçi programlarda istenmeyen sonuçlar doğurur. Go paradigmasında, olayların beklenmesi yönetimini kanallar ve select/time.After ile kurmak daha doğrudur.

Çözüm:

time.Sleep(d) geçerli iş parçacığını d süre boyunca bloke eder, bu doğrudan bir "uyku"dur. time.After(d) bir kanalı döndürür, bu kanalda d süresi içinde bir olay zamanlanır. Son seçim, select ile kanallarda çok daha esnektir, kesintiye uğratılabilir beklemeler ve zaman aşımı için uygundur.

Kod örneği:

ch := make(chan struct{}) go func() { time.Sleep(2 * time.Second) ch <- struct{}{} }() select { case <-ch: fmt.Println("tamam") case <-time.After(1 * time.Second): fmt.Println("zaman aşımı") }

Anahtar özellikler:

  • time.After, zaman aşımlarını uygulamak için select ile harika bir şekilde birleşir.
  • time.Sleep, yalnızca geçerli iş parçacığını bloke eder, akışı/prosesi değil.
  • time.After her seferinde yeni bir kanal yaratır, eski kanallar değer okunana kadar serbest bırakılmaz.

Püf noktaları içeren sorular.

time.Sleep'i tüm programın çalışmasını bloke etmek için kullanabilir miyiz?

Hayır, time.Sleep yalnızca tek bir iş parçacığını "uykuya" dalmasına neden olur, diğerleri çalışmaya devam eder.

time.After bellek sızıntısına neden olabilir mi, eğer kanal okunmazsa?

Evet, zamanlayıcı, değer okunana kadar askıda kalır; okumazsanız, çöp toplayıcı nesneyi silmez.

Kod örneği:

func leak() { for { _ = time.After(time.Hour) } }

time.After ile olay alınmadığında beklemeyi nasıl doğru bir şekilde iptal ederiz?

Bir zamanlayıcı oluşturmak ve eğer süre dolmadan beklemeyi sonlandırmanız gerekiyorsa, manuel olarak durdurmak daha iyidir:

t := time.NewTimer(time.Minute) if done { t.Stop() }

Yaygın hatalar ve anti-paternlere

  • Kanallar ve select yerine çalışan iş parçacıklarında time.Sleep kullanmak.
  • time.After'dan okumadığınızda zamanlayıcı sızıntılarına neden olmak.
  • Değerleri okumak için yeterince zaman ayırmadan döngüde time.After oluşturmak.

Gerçek hayattan bir örnek

Olumsuz durum

Bir iş parçacığı bir sinyal bekliyor ve zaman aşımı durumunda şöyle yapıyor:

time.Sleep(10*time.Second) doSomething()

Artıları:

  • Zaman gecikmesi eklemek kolay.

Eksileri:

  • Sinyal önceden alınmışsa veya çalışmasına gerek yoksa — gereksiz uyku, zamanlama hataları riski.
  • Her şey iptal edilemez, iptal önce olursa "uyandırmak" zor.

Olumlu durum

Kod, select ve time.After ile oluşturulur:

select { case <-workSignal: // Uygulamak case <-time.After(10 * time.Second): // Zaman aşımında yapmak }

Artıları:

  • Bekleme-zaman aşımı birbirinin yerine geçebilir, iptali simüle etmek daha kolay.
  • Beklemeyi en aza indirgeme.

Eksileri:

  • Kodu okumak biraz daha zor, select ve kanalların çalışma mantığını anlamak gereklidir.