Select İfadesi
Coddy'nin GO Journey'sinin Nesne Yönelimli Programlama bölümünün bir parçası — ders 62 / 107.
select ifadesi, bir goroutine'in aynı anda birden fazla kanal işlemi üzerinde beklemesini sağlar. Bir switch ifadesine benzer, ancak her bir case bir kanal gönderimi veya alımı içerir. Birden fazla kanal hazır olduğunda, select rastgele birini seçer.
func main() {
ch1 := make(chan string)
ch2 := make(chan string)
go func() { ch1 <- "from channel 1" }()
go func() { ch2 <- "from channel 2" }()
select {
case msg1 := <-ch1:
fmt.Println(msg1)
case msg2 := <-ch2:
fmt.Println(msg2)
}
}select olmadan, ch1 kanalından veri almak veri gelene kadar bloklanır ve bu durum ch2 üzerindeki verinin potansiyel olarak kaçırılmasına neden olabilir. select ile, hangi kanal önce veri alırsa o işlenir.
default durumu select ifadesini bloklamayan (non-blocking) hale getirir; hiçbir kanal hazır değilse anında çalışır:
select {
case msg := <-messages:
fmt.Println("Received:", msg)
default:
fmt.Println("No message available")
}Yaygın bir desen, select ifadesini, belirtilen süreden sonra bir değer alan bir kanal döndüren time.After kullanarak zaman aşımlarıyla birleştirir:
select {
case result := <-ch:
fmt.Println("Got result:", result)
case <-time.After(2 * time.Second):
fmt.Println("Timeout!")
}Bu, bir kanal işleminin hiçbir zaman tamamlanmayabileceği durumlarda programınızın sonsuza kadar beklemesini engeller.
Görev
KolayBirden fazla eşzamanlı veri kaynağını işlemek için select ifadesini kullanan bir servis monitörü oluşturalım. Monitörünüz farklı servis kanallarını aynı anda dinleyecek ve veri geldiğinde veya hiçbir güncelleme olmadığında uygun şekilde yanıt verecektir.
Kodunuzu iki dosya halinde düzenleyeceksiniz:
monitor.go: Select tabanlı kanal işleme ile servis izleme mantığınızı tanımlayın.Name(string) veStatus(string) alanlarına sahip birServiceUpdateyapısı (struct) oluşturun.Üç kanal alan bir
Monitorfonksiyonu uygulayın:primary chan ServiceUpdate,backup chan ServiceUpdatevedone chan bool. Bu fonksiyon, her üç kanalı da aynı anda dinlemek içinselectkullanmalıdır:primarykanalından veri alındığında:Primary: [Name] is [Status]şeklinde formatlanmış dizeyi döndürün.backupkanalından veri alındığında:Backup: [Name] is [Status]şeklinde formatlanmış dizeyi döndürün.donekanalından veri alındığında:Monitoring stoppeddöndürün.
Tek bir
updates chan ServiceUpdatealan ve bloklamayan (non-blocking) bir kontrol gerçekleştirmek içindefaultdurumuyla birlikteselectkullanan birCheckStatusfonksiyonu uygulayın:- Eğer bir güncelleme mevcutsa:
Update available: [Name]döndürün. - Eğer güncelleme mevcut değilse (default durumu):
No updates pendingdöndürün.
main.go: Kanalları kurun ve hem bloklayan hem de bloklamayan select davranışını gösterin.Hangi senaryonun çalıştırılacağını belirleyen bir modu girdiden okuyun:
primary,backup,stopveyacheck.primary,backupvestopmodları için: ayrıca bir servis adı ve durumu okuyun. Üç kanalı oluşturun, moda bağlı olarak uygun kanala veri gönderen bir goroutine başlatın, ardındanMonitorfonksiyonunu çağırın ve sonucunu yazdırın.checkmodu için: bir servis adı ve durumu, ayrıca kontrol etmeden önce veri gönderilip gönderilmeyeceğini belirten bir bayrak (sendveyanosend) okuyun. 1 kapasiteli bir tamponlu (buffered) kanal oluşturun. Eğer bayraksendise,CheckStatusfonksiyonunu çağırmadan önce kanala bir güncelleme gönderin.CheckStatussonucunu yazdırın.
Aşağıdaki girdiler sağlanacaktır:
- Satır 1: Mod (
primary,backup,stopveyacheck) - Satır 2: Servis adı
- Satır 3: Servis durumu
- Satır 4 (sadece
checkmodu için):sendveyanosend
Örneğin, şu girdi verildiğinde:
primary
Database
healthyÇıktınız şu olmalıdır:
Primary: Database is healthyVe şu girdi verildiğinde:
check
Cache
active
nosendÇıktınız şu olmalıdır:
No updates pendingKopya kağıdı
select ifadesi, bir goroutine'in aynı anda birden fazla kanal işlemi üzerinde beklemesine olanak tanır. Bir switch ifadesi gibi çalışır, ancak her durum (case) bir kanal gönderimi veya alımı içerir:
select {
case msg1 := <-ch1:
fmt.Println(msg1)
case msg2 := <-ch2:
fmt.Println(msg2)
}Birden fazla kanal hazır olduğunda, select rastgele birini seçer. select olmadan, bir kanaldan veri almak bloklanmaya neden olur ve potansiyel olarak başka bir kanaldaki verilerin kaçırılmasına yol açardı.
default durumu select ifadesini bloklamayan (non-blocking) hale getirir; eğer hiçbir kanal hazır değilse anında çalışır:
select {
case msg := <-messages:
fmt.Println("Received:", msg)
default:
fmt.Println("No message available")
}Yaygın bir desen, select ifadesini, belirtilen süre sonunda bir değer alan bir kanal döndüren time.After kullanarak zaman aşımlarıyla (timeouts) birleştirmektir:
select {
case result := <-ch:
fmt.Println("Got result:", result)
case <-time.After(2 * time.Second):
fmt.Println("Timeout!")
}Bu, bir kanal işleminin asla tamamlanmama ihtimaline karşı programınızın sonsuza kadar beklemesini engeller.
Kendin dene
package main
import (
"fmt"
)
func main() {
var mode string
fmt.Scanln(&mode)
var serviceName string
fmt.Scanln(&serviceName)
var serviceStatus string
fmt.Scanln(&serviceStatus)
// TODO: Farklı modları işle: "primary", "backup", "stop", "check"
// "primary", "backup", "stop" modları için:
// - Üç kanal oluşturun: primary, backup, done
// - Uygun kanala veri gönderen bir goroutine başlatın
// - Monitor fonksiyonunu çağırın ve sonucu yazdırın
// "check" modu için:
// - Ek bayrağı okuyun ("send" veya "nosend")
// - 1 kapasiteli bir tamponlu kanal oluşturun
// - Eğer bayrak "send" ise, kanala bir güncelleme gönderin
// - CheckStatus fonksiyonunu çağırın ve sonucu yazdırın
}
Bu ders kısa bir quiz içerir. Soruları yanıtlamak ve ilerlemeni kaydetmek için derse başla.
Nesne Yönelimli Programlama bölümündeki tüm dersler
1Go OOP Temelleri
Harici DosyalarGo Çalışma Alanı ve ModüllerPaketler ve İçe AktarmalarDışa Aktarılan ve Aktarılmayan İsimlerGo'da OOP'ye GirişSınıf Olarak Struct'larStruct'larda Metot TanımlamaPointer ve Değer AlıcılarStruct BaşlatmaYapıcı FonksiyonlarÖzet - Basit Hesap Makinesi4Arayüzler
Arayüzlere GirişÖrtük UygulamaSözleşme Olarak ArayüzBoş Arayüz (any)Tür OnaylamaTür SeçimiArayüz BileşimiStringer ve Error ArayüzleriÖzet - Şekil Hesaplayıcı7Kapsülleme
Dışa Aktarılan ve Aktarılmayan AlanlarPaket Seviyesinde KapsüllemeGetter ve Setter MetotlarıGo'da Bilgi GizlemeÖzet - Öğrenci Kayıtları10Generics (Go 1.18+)
Generics'e GirişTür ParametreleriTür KısıtlamalarıGeneric Struct'larGeneric Metotlar İçin Geçici ÇözümÖzet - Generic Koleksiyon13Tasarım Kalıpları Bölüm 1
Tasarım Kalıplarına GirişSingleton KalıbıFactory KalıbıAbstract Factory KalıbıObserver KalıbıStrategy Kalıbı2Türler ve Struct'lar: Derinlemesine İnceleme
Temel ve Bileşik TürlerÖzel Tür TanımlamalarıStruct EtiketleriAnonim Struct'larİç İçe Geçmiş Struct'larSıfır Değerler ve VarsayılanlarÖzet - Rehber5Kalıtım Yerine Kompozisyon
Go'da Neden Kalıtım YokStruct Gömme TemelleriMetot YükseltmeBirden Fazla Struct GömmeGömme vs AgregasyonGömülü Metotları GölgelemeÖzet - Çalışan Hiyerarşisi8Hata Yönetimi ve OOP
error ArayüzüÖzel Hata TürleriHata Sarmalama (fmt.Errorf)Sentinel Hatalarerrors.Is() ve errors.As()Panic, Defer ve RecoverÖzet - Dosya Ayrıştırıcı3İşaretçiler ve Bellek
Go'da İşaretçi TemelleriStruct İşaretçileriDeğer ile Geçme ve Referans ile Geçmenew() FonksiyonuGo'da Garbage CollectionÖzet - Linked List Oluşturucu6Go'da Polimorfizm
Interface'ler ile PolimorfizmGo'da Duck TypingInterface Karşılama KurallarıPolimorfik KoleksiyonlarDependency InjectionÖzet - Payment Processor9Eşzamanlılık ve OOP
Goroutine TemelleriKanallar ve İletişimTamponlu ve Tamponsuz KanallarSelect İfadesisync.Mutex ve sync.RWMutexsync.WaitGroupThread-Safe Struct TasarımıÖzet - Worker Pool