Menu
Coddy logo textTech

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.

challenge icon

Görev

Kolay

Arabelleğ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) ve ID (string) alanlarına sahip bir Value yapı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 - cherry

Arabellek 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
}
quiz iconKendini test et

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

Kendi başına pratik yap: Online Go derleyicisi