Tamponlu ve Tamponsuz Kanallar
Coddy'nin GO Journey'sinin Nesne Yönelimli Programlama bölümünün bir parçası. Ders 61 / 107.
Şimdiye kadar kullandığımız kanallar arabelleksiz kanallardır. Değerleri tutacak kapasiteleri yoktur. Bir gönderme işlemi, başka bir goroutine alana kadar engellenir ve bunun tersi de geçerlidir. Arabelleğe alınmış kanallar dahili depolama ekleyerek gönderimlerin, hemen bir alıcı olmadan tamamlanmasına olanak tanır.
make'e bir kapasite geçirerek arabelleğe alınmış bir kanal oluşturun:
// Tamponsuz - kapasite 0
unbuffered := make(chan int)
// Tamponlu - kapasite 3
buffered := make(chan int, 3)Tamponlanmış bir kanalda, gönderme işlemleri yalnızca tampon dolu olduğunda, alma işlemleri ise yalnızca tampon boş olduğunda engellenir:
ch := make(chan string, 2)
ch <- "first" // engellemez - buffer'da yer var
ch <- "second" // engellemez - buffer'da yer var
// ch <- "third" engellerdi - buffer dolu
fmt.Println(<-ch) // "first"
fmt.Println(<-ch) // "second"Arabellekte şu anda kaç öğe olduğunu kontrol etmek için len(ch), toplam kapasite için ise cap(ch) kullanın.
Her birini ne zaman kullanmalı: Tamponlanmamış kanallar sıkı bir eşzamanlama sağlar: gönderici, alıcının değeri aldığını bilir. Tamponlanmış kanallar, gönderici ve alıcının zamanlamasını birbirinden bağımsız hâle getirir; üreticiler ve tüketiciler farklı hızlarda çalıştığında kullanışlıdır. Ancak tamponlanmış kanallar eşzamanlama hatalarını gizleyebilir; bu nedenle tamponlama için özel bir nedeniniz yoksa tamponlanmamış kanalları tercih edin.
Görev
KolayArabelleğe alınmış ve alınmamış kanallar arasındaki farkı gösteren bir toplu işlemci oluşturalım. Bir üreticinin öğeleri bir işlemciye gönderdiği, zamanlamalarını birbirinden ayırmak ve üreticinin önceden çalışmasına izin vermek için arabelleğe alınmış kanallar kullanan bir sistem oluşturacaksın.
Kodunu iki dosyaya düzenleyeceksin:
processor.go: Kanalları kullanarak toplu işleme mantığını tanımla.Item(int) veID(string) alanlarına sahip birValueyapısı oluştur.İki işlev uygula:
Producer(items []Item, out chan Item)- Her öğeyi çıktı kanalına gönderir. Her öğeyi gönderdikten sonra şunu yazdır:Produced item [ID]. Tüm öğeler gönderildikten sonra,len(out)kullanarak arabellekte bekleyen öğelerin mevcut sayısını şu biçimde yazdır:Buffer has [count] items. Ardından kanalı kapat.Consumer(in chan Item) []string- Girdi kanalından öğeleri alır ve bunları biçimlendirilmiş dizelerden oluşan bir dilimde toplar. Alınan her öğe için dize şu şekilde olmalıdır:Consumed: [ID] - [Value]. Kanal kapatıldığında dilimi döndür.
main.go: Arabelleğe alınmış kanalı kur ve üretici ile tüketiciyi koordine et.Arabellek kapasitesini, ardından öğe sayısını ve sonrasında her öğenin kimliği ile değerini oku. Belirtilen kapasiteye sahip arabelleğe alınmış bir kanal oluştur. Arabelleği doldurmak için önce Producer işlevini (goroutine olarak değil) çalıştır, ardından tüm öğeleri işlemek üzere Consumer işlevini çalıştır. Tüketilen her sonucu ayrı bir satırda yazdır.
Aşağıdaki girdiler sağlanacaktır:
- 1. satır: Arabellek kapasitesi (tamsayı)
- 2. satır: Öğe sayısı (tamsayı)
- Sonraki satırlar: Her öğe için iki satır — öğe kimliği (tamsayı), ardından değeri (dize)
Örneğin, şu verildiğinde:
3
3
1
apple
2
banana
3
cherryÇıktın şu şekilde olmalıdır:
Produced item 1
Produced item 2
Produced item 3
Buffer has 3 items
Consumed: 1 - apple
Consumed: 2 - banana
Consumed: 3 - cherryArabellek kapasitesi 3 olduğunda üreticinin 3 öğenin tamamını engellenmeden gönderebildiğine ve tüketici başlamadan önce arabellekte 3 öğe beklediğinin görüldüğüne dikkat et. Arabellek öğe sayısından küçük olsaydı üretici yer açılmasını beklerken engellenecekti.
Kendin dene
package main
import (
"bufio"
"fmt"
"os"
"strconv"
"strings"
)
func main() {
reader := bufio.NewReader(os.Stdin)
// Tampon kapasitesini oku
line, _ := reader.ReadString('\n')
bufferCapacity, _ := strconv.Atoi(strings.TrimSpace(line))
// Öğe sayısını oku
line, _ = reader.ReadString('\n')
numItems, _ := strconv.Atoi(strings.TrimSpace(line))
// Her öğenin ID ve değerini oku
items := make([]Item, numItems)
for i := 0; i < numItems; i++ {
line, _ = reader.ReadString('\n')
id, _ := strconv.Atoi(strings.TrimSpace(line))
line, _ = reader.ReadString('\n')
value := strings.TrimSpace(line)
items[i] = Item{ID: id, Value: value}
}
// TODO: Belirtilen kapasiteye sahip tamponlu bir kanal oluştur
// TODO: Tamponu doldurmak için Producer'ı (goroutine olarak değil) çalıştır
// TODO: Tüm öğeleri işlemek için Consumer'ı çalıştır
// TODO: Tüketilen her sonucu ayrı bir satıra yazdır
}
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 PoolKendi başına pratik yap: Online Go derleyicisi