---
title: 'select Deyimi'
source: 'https://academia.sh/tr/kurslar/go-eszamanlilik/select-deyimi'
course: Eşzamanlılık
language: tr
updated: '2026-08-23T16:55:16+00:00'
license: 'CC BY-SA 4.0'
---

# select Deyimi

Birden çok kanal üzerinde aynı anda beklemenin karşılığı select deyimidir: yalnız bir dal hazırsa o dal belirlenimci biçimde seçilir, hiçbiri hazır değilse ve bir default dalı varsa o dal seçilir. Yazım sırası bir öncelik taşımaz. Sınırlayıcı ölçüm: iki dal aynı anda hazırsa seçim rastgeledir ve bu durum koşturulmuyor, yalnızca modelleniyor — rastgelelik dilin kendi kararı.

Önceki ders bir kanalın kapasitesinin engellemeyi nerede başlattığını ölçtü ve `select` ile
`default`'u yalnız **tek bir** kanalı yoklamak için kullandı. Ama bir goroutine çoğu zaman
birden çok kaynaktan aynı anda haber bekler: birkaç sonuç kanalından biri hazır olabilir, bir
iptal sinyali gelebilir, bir zaman aşımı dolabilir. `select` deyimi bunun için var — birden
çok kanal üzerinde aynı anda bekleyip **hangisi önce hazır olursa** onu işleyen tek yapı.

Bu ihtiyaç, tek bir kanalı beklemenin yetmediği her yerde ortaya çıkıyor. Bir goroutine
yalnız bir kanalı beklerken `<-kanal` yazmak yeterlidir; ama iki ayrı kaynaktan **hangisi
önce** gelirse onu işlemek isteyen bir goroutine, bunu tek bir alım ifadesiyle yazamaz.
`select` tam olarak bu boşluğu dolduruyor.

Bir `select` bloğu, her biri bir kanal işlemiyle başlayan birden çok `case` içerir. Deyim bu
işlemlerden hazır olanlardan birini seçip o dalı çalıştırır; hiçbiri hazır değilse ve bir
`default` dalı varsa hemen o çalışır, yoksa `select` en az bir dal hazır olana kadar bekler.
Bu ders bu seçimin nasıl belirlendiğini, nerede belirlenimci nerede rastgele olduğunu ölçüyor.

`select`in her dalı bir gönderim ya da bir alım olabilir; aynı `select` içinde bazı dallar
gönderim, bazıları alım olabilir, önemli olan yalnızca hangisinin **o an** engellemeden
tamamlanabileceğidir. Bu, `select`i bir `switch`ten ayıran ilk fark: `switch` bir değeri
sırayla dallarla karşılaştırırken, `select` her dalın kendi kanal işlemini **aynı anda**
dener ve hangisi hazırsa ona göre karar verir. Bir kanal işlemi olmayan bir `case` yazmak
derlenmez; `select`in dalları her zaman bir gönderim ya da alımla başlar.

Bir `select`in kaç dalı olabileceğine dilde bir üst sınır yok; bir `select` bloğu iki
kanalı da, on kanalı da bekleyebilir. Bu ders yalnızca iki kanallı örnekler kullanıyor,
çünkü ölçülen kurallar — belirlenimli seçim, sıra bağımsızlığı, rastgelelik — dal
sayısından bağımsız; iki dal bu kuralları göstermek için yeterli ve okunması en kolay
durum. Dal sayısı arttıkça ölçülen kurallar değişmiyor, yalnızca aynı anda hazır
olabilecek dal sayısı artıyor; üçüncü bölümdeki rastgelelik kuralı da ikiden fazla dal
hazır olduğunda aynı biçimde geçerli kalıyor.

## Tek Dal Hazırken Seçim Belirlenimlidir

Bir `select` içindeki dallardan yalnız biri hazırsa, `select` başka hiçbir seçenek
düşünmeden o dalı çalıştırır. Hiçbiri hazır değilse ve bir `default` dalı varsa, `select`
hiç beklemeden o dala düşer — önceki derste kapasiteyi yoklamak için kullanılan tam olarak
bu davranıştı.

```go
// tekilVeVarsayilan.go — yalniz bir dal hazirken secim belirlenimli, hicbiri hazir degilken varsayilan dal secilir
package main

import "fmt"

func sec(a, b chan string) string {
	select {
	case v := <-a:
		return "a: " + v
	case v := <-b:
		return "b: " + v
	default:
		return "varsayilan: hicbiri hazir degil"
	}
}

func main() {
	a := make(chan string, 1)
	b := make(chan string, 1)

	fmt.Println("hicbiri hazir degilken:", sec(a, b))

	a <- "ilk deger"
	fmt.Println("yalniz a hazirken     :", sec(a, b))

	b <- "ikinci deger"
	fmt.Println("yalniz b hazirken     :", sec(a, b))
}
```

```
hicbiri hazir degilken: varsayilan: hicbiri hazir degil
yalniz a hazirken     : a: ilk deger
yalniz b hazirken     : b: ikinci deger
```

**GK14.** — Üç çağrı da aynı `sec` fonksiyonunu, aynı kaynak koduyla çağırıyor; değişen
tek şey kanalların doluluğu. İlk çağrıda ikisi de boş, `default` seçiliyor. `a`ya bir
değer konduğunda ikinci çağrı `a` dalını seçiyor ve bu arada `a`daki değeri **tüketiyor**
— `a` şimdi yine boş. Üçüncü çağrıda yalnız `b` doluyken `b` dalı seçiliyor. Hiçbir
çağrıda birden fazla dal aynı anda hazır olmadı; bu yüzden her üç sonuç da kesinlikle
tekrarlanabilir.

Bu ölçümün tek goroutine içinde, hiç eşzamanlılık gerektirmeden yapılabilmesi önemli: `a`
ve `b` kanallarına doğrudan ana goroutine'den değer konuluyor, hiçbir goroutine
başlatılmıyor. Bu, `select`in kendisinin eşzamanlılığa özgü bir yapı olmadığını gösteriyor
— `select` yalnız birden çok kanal işlemi arasında seçim yapan bir dildir; kanalların
karşı tarafında goroutine olup olmaması `select`in kendi davranışını değiştirmiyor. Sonraki
derslerde `select` hep goroutine'ler arasında kullanılacak, ama bu ders onun çekirdek
davranışını en yalın hâliyle, tek goroutine'de gösteriyor.

Bu ayrım küçük görünse de önemli: `select`in belirlenimli davranışı zamanlamadan değil,
yalnızca **hangi kanalların o an dolu olduğundan** kaynaklanıyor. Aynı kod, kanalları
farklı bir sırayla doldursaydı ya da farklı bir makinede çalıştırılsaydı sonuç yine aynı
olurdu — çünkü belirleyici olan zamanlama değil, doluluk durumunun kendisi.

## Yazım Sırası Bir Öncelik Değildir

`select`in dalları yukarıdan aşağı bir öncelik sırası taşımaz — bu, sıradan bir `if`/`else
if` zincirinden ya da bir `switch`ten temel bir farktır. Hazır olan tek dal hangi sırada
yazılmış olursa olsun seçilir; yazım sırası yalnızca okunabilirlik içindir, çalışma zamanı
davranışını etkilemez.

```go
// siraOnemsiz.go — select dallarinin yazim sirasi hangi dalin secilecegini belirlemez
package main

import "fmt"

func sec(a, b chan string) string {
	select {
	case v := <-b:
		return "b: " + v
	case v := <-a:
		return "a: " + v
	}
}

func main() {
	a := make(chan string, 1)
	b := make(chan string, 1)
	a <- "sadece a doldu"

	fmt.Println(sec(a, b))
}
```

```
a: sadece a doldu
```

**GK15.** — Bu fonksiyonda `b` dalı kaynakta **önce**, `a` dalı **sonra** yazılı. Yalnız
`a` doluyken çalıştırıldığında sonuç yine `a: sadece a doldu` — kaynaktaki sıralamanın
sonucu değiştirmediğini gösteriyor. `select`in her `case`i eşit ağırlıkta değerlendirilir;
hazır olan tek dal neyse o çalışır. Bu, bir sonraki bölümün sorusunu doğuruyor: iki dal
**aynı anda** hazır olsaydı ne olurdu, madem sıralama bir öncelik vermiyor?

Bu davranış, `select`in dallarını değerlendirme biçimiyle ilgili. Kaynakta yazılan sıra
yalnızca derleyicinin `case`leri okuma sırasıdır; çalışma zamanında `select`, çalıştırılacağı
anda dalların **tümünü** birden değerlendirip hazır olanları bulur, sonra bunlar arasından
seçer. Sıradan bir `if a != nil { ... } else if b != nil { ... }` zincirinde ilk koşulu
sağlayan dal kazanırdı — orada yazım sırası gerçekten bir önceliktir. `select` bu modele
uymuyor; bu fark, `select`i öğrenirken en sık karışan noktalardan biri, çünkü sözdizimi
`switch`e çok benziyor ama değerlendirme kuralı farklı.

## Sınırlayıcı Ölçüm: İki Dal Birden Hazırsa Seçim Rastgeledir

Buraya kadarki her ölçüm, herhangi bir anda **en fazla bir** dalın hazır olduğu durumları
kurdu. İki dal aynı anda hazır olduğunda dil hangi kuralı uygular? Go'nun kendi belirtimi
bu soruya açık bir yanıt veriyor: birden çok dal aynı anda hazırsa, `select` aralarından
**tekdüze rastgele** birini seçer. Bu, kursun bu derse kadarki her ölçümünün dayandığı
belirlenimcilik kuralının **bilinçli bir istisnası** — ve bu yüzden bu ders bu durumu
**koşturmuyor**, yalnızca modelliyor.

```go
// modellenir.go — iki dal ayni anda hazirsa secim rastgeledir; bu ders bu dali kosturmaz, yalniz gosterir
package main

func ikiDalBirdenHazirsaSecim(a, b chan string) string {
	select {
	case v := <-a:
		return "a: " + v
	case v := <-b:
		return "b: " + v
	}
}
```

**GK16.** — Bu fonksiyon, `a` ve `b`nin ikisi de dolu çağrıldığında `select`in tam olarak
karşılaştığı durumu gösteriyor: derleyici burada iki dal arasında sabit bir tercih
yapmıyor, çalışma zamanı her çağrıda yeniden rastgele seçiyor. `ikiDalBirdenHazirsaSecim`
bu dersin hiçbir yerinde çağrılmıyor — çağrılsaydı, iki koşum arasında farklı sonuçlar
üretebilirdi ve bu, kod_dogrula'nın aradığı "her koşumda aynı çıktı" koşulunu bilerek
bozardı. Fonksiyon yalnızca **var olduğu için** derleniyor; kaynağın kendisi rastgeleliğin
nerede ortaya çıktığını gösteriyor, koşumu değil.

Bu rastgelelik bir eksiklik değil, bilinçli bir tasarım kararı. Eğer `select` iki hazır
dal arasında hep kaynaktaki ilk dalı seçseydi, programcılar zamanla bu sırayı bir öncelik
kuralı gibi kullanmaya başlar ve kanallardan birinin sistematik olarak açlığa
düşmesine yol açabilirdi — art arda aynı iki dal sürekli hazır kaldığında, ikinci dal
hiç çalışmayabilirdi. Rastgele seçim bu riski dilin kendisi ortadan kaldırıyor: hiçbir
dal, yalnızca kaynakta önce yazıldığı için sistematik olarak öne geçemiyor.

Bu ölçülemezlik, önceki bölümdeki "yazım sırası bir öncelik değildir" bulgusunun asıl
gerekçesi. Sıra bir öncelik taşısaydı, iki dal aynı anda hazır olduğunda hangisinin
seçileceği yine belirlenimci olurdu — ilk yazılan kazanırdı. Sıranın hiçbir ağırlığı
olmadığı için, iki dal birden hazır olduğunda gerçekten seçilecek bir kural kalmıyor;
dil bu boşluğu rastgelelikle dolduruyor, M09/K01 Go Temelleri kursunda görülen "tanımlı"
sınıfından farklı bir yol: orada yazılmayan bir şeyin yerine **sabit** bir değer
konuyordu, burada yazılmayan bir şeyin yerine her seferinde **yeniden çekilen** bir
değer konuyor. Bu ders bu ayrımı bir eksen olarak sürdürmüyor, yalnız bir kez not ediyor.

Bu ders `ikiDalBirdenHazirsaSecim`i hiç çağırmadığı için, iki koşum arasındaki farkı
göstermenin tek yolu kaynağı okumak. Bu, kursun M09/K03'e kadarki bütün derslerinin
aksine, "aynı kaynak farklı koşumlarda farklı sonuç verebilir" iddiasının **koşturmadan**
kanıtlandığı tek yer: rastgeleliğin varlığını Go'nun kendi belirtimi garanti ediyor, bu
ders yalnız o garantinin nerede devreye girdiğini kaynak üzerinde gösteriyor.

## select Bloklamayan Bir Denetim Aracıdır

`default` dalı `select`i yalnızca bir yoklama aracına değil, akışı hiç durdurmadan devam
ettiren bir denetim aracına dönüştürüyor. Bu, bir kanaldaki bütün hazır değerleri, hiçbiri
kalmayana kadar tüketmek için kullanılabilir — kanal boşaldığı anda döngü, beklemeden
kendini durdurur.

Bu kullanım, `select`in iki farklı işlevini birbirinden ayırıyor. Birinci bölümdeki
kullanımda `select` birden çok kanal arasında **seçim** yapıyordu — hangi kaynağın hazır
olduğunu belirliyordu. Burada `select` tek bir kanal üzerinde, o kanalın hazır olup
olmadığını **sormak** için kullanılıyor; `default` dalının varlığı, "hazır değilse bekleme"
demenin dildeki karşılığı. İki kullanım da aynı sözdizimini paylaşıyor, ama amaçları
farklı: biri birden çok kaynak arasında karar veriyor, öteki tek bir kaynağın anlık
durumunu okuyor.

```go
// engellenmeyenDenetim.go — select, hazir olmayan bir kanali beklemeden akisi surdurmek icin kullanilir
package main

import "fmt"

func hazirsaAl(kanal chan int) (int, bool) {
	select {
	case v := <-kanal:
		return v, true
	default:
		return 0, false
	}
}

func main() {
	sonuclar := make(chan int, 3)
	sonuclar <- 10
	sonuclar <- 20

	toplam, adet := 0, 0
	for {
		v, tamam := hazirsaAl(sonuclar)
		if !tamam {
			break
		}
		toplam += v
		adet++
	}
	fmt.Println("kanaldan engellenmeden alinan deger sayisi:", adet, "toplam:", toplam)

	_, tamam := hazirsaAl(sonuclar)
	fmt.Println("kanal bosalinca uzerine deneme            :", tamam)
}
```

```
kanaldan engellenmeden alinan deger sayisi: 2 toplam: 30
kanal bosalinca uzerine deneme            : false
```

**GK17.** — `sonuclar` kanalına yalnızca iki değer konuldu; döngü bu ikisini `hazirsaAl`
ile tüketiyor ve üçüncü denemede `tamam` `false` döndüğü için döngü kendiliğinden
duruyor — hiçbir goroutine beklenmedi, hiçbir sıra çizelgeleyiciye bırakılmadı. Bu
düzenek, bir kanalın "şu an elimde ne var" diye sorulmasını sağlıyor; kanalın kendisi
boşsa, soran taraf beklemeden yoluna devam edebiliyor. Bu, önceki derste tampon
kapasitesini yoklamak için kullanılan tekniğin genel biçimi: orada tek bir kanalın dolu
olup olmadığı soruluyordu, burada aynı teknik bir kanalı **tüketmek** için kullanılıyor.

Döngünün durma koşulu da dikkat çekici: `for` döngüsü sabit bir sayıya göre değil,
`hazirsaAl`in döndürdüğü ikinci değere göre duruyor. Kaynak koddan kaç kez döneceği
okunamaz — `sonuclar` kanalına kaç değer konulmuş olursa olsun aynı döngü çalışır ve
tam olarak o kadar adımda durur. Bu, `range` ile bir dilim gezmekten farklı: `range`in
kaç kez döneceği dilimin uzunluğundan **önceden** okunabilirken, bu döngünün kaç kez
döneceği yalnızca koşarak öğrenilir. Bu fark, kapanış dersinin ölçtüğü `range over
channel` davranışıyla karşılaştırıldığında daha da netleşiyor: `range` bir kanalın
**kapanmasını** bir durma koşulu sayarken, buradaki döngü kanalın o anki **doluluğunu**
bir durma koşulu sayıyor — ikisi de sonlu bir döngü üretir, ama farklı bir sinyale göre.

Bu kullanım biçiminin bir bedeli var: `hazirsaAl` bir goroutine'in üretmesini **beklemez**,
yalnızca o anda hazır olanı alır. Kanala henüz hiçbir şey yazılmamışsa, `hazirsaAl` her
zaman `false` döner — üretici goroutine bir mikrosaniye sonra bir değer gönderecek olsa
bile. Bloklamayan bir denetim aracı, karşılığında beklemeyi de kaybeder; hangisinin
gerektiği, ne zaman `select`in beklemesine izin verileceği, ne zaman hemen devam etmesi
gerektiğine bağlı bir tasarım kararı.

Bu tehlike, `default` dalını bir döngü içine koymanın yanlış kullanımıyla daha da
belirginleşiyor: eğer amaç bir değerin gelmesini beklemekse ve döngü `default` dalına her
düştüğünde hemen tekrar denerse, program hiçbir zaman bloklanmadan, işlemciyi sürekli
meşgul ederek bekler — bu, kilit ve kritik bölge bağlamında M01/K05 İşletim Sistemi
Kavramları kursunda kurulmuş **meşgul bekleme** kalıbının `select` üzerindeki karşılığı.
Bu ders o kalıbı kurmuyor: `hazirsaAl` bir kez çağrılıyor, bir döngüde beklenmiyor.
Beklemek gerektiğinde doğru araç `default`suz bir `select`tir — o zaman `select` kendisi
hazır bir dal olana kadar bloklanır ve işlemciyi meşgul etmez; bu, birinci bölümdeki
`sec` fonksiyonunun `default` dalı olmadan yazılmış hâli olurdu.

## Özet

- `select`, birden çok kanal işleminden yalnızca **bir tek** dalın hazır olduğu durumda
  o dalı belirlenimci biçimde seçer.
- Dalların kaynaktaki yazım sırası bir öncelik taşımaz; hazır olan dal hangi sırada
  yazılmış olursa olsun seçilir.
- Hiçbir dal hazır değilken bir `default` dalı varsa hemen çalışır; `select` bu şekilde
  hiç beklemeyen bir yoklama ve denetim aracına dönüşür.
- İki dal aynı anda hazır olduğunda seçim tekdüze rastgeledir; bu kursun ölçtüğü
  belirlenimcilik kuralının bilinçli istisnasıdır ve bu yüzden koşturulmaz, yalnız
  modellenir.
- `select`+`default` bir kanalı, hiçbir goroutine beklemeden, elindeki değerler bitene
  kadar tüketmek için kullanılabilir.
- `default`suz bir `select` hiçbir dal hazır olmayınca bloklanır ve işlemciyi meşgul
  etmez; beklemek gerektiğinde doğru araç budur, `default`lı bir döngü değil.

## Sonraki Adım

Bu derste kapanan bir kanalın `select` içindeki davranışına hiç değinilmedi. Kapanmış bir
kanaldan alım da tıpkı dolu bir kanaldan alım gibi bir `select` dalını hemen hazır kılar —
ama gelen yanıt, ölçülen değerin kendisi değil, kanalın **artık boş kalacağının** haberi.
Sıradaki ders bu son davranışı ölçüyor: bir kanalın kapatılması bir sonlanma sinyalidir, ve
bu sinyal hem `range` hem de doğrudan alımda kendini nasıl gösteriyor.
