11# Ders 12: Channels
22
3- Bazı durumlarda thread'ler arasında veri aktarımı gerekebilir. Channel enstrümanı farklı thread'ler arasında veri
4- taşınması için kullanılmaktadır . Rust standart kütüphanesi varsayılan olarak ** Multi Producer - Single Consumer** türünü
5- destekler. Farklı senaryolar için tokio, crossbeam gibi küfelerden de yararlanılabilir. ** MPSC** senaryosunda producer
6- yani veri yayımını gerçekleştiren n sayıda iş parçacığı varken tek bir tüketici ya da dinleyici söz konusudur. Kanallar
7- aşağıdaki gibi senaryolarda sıklıkla tercih edilir;
8-
9- - Görev _ (task)_ sonuçlarının ana bir thread içerisine toplanması
10- - HTTP isteklerinin paralel olarak işlenmesi
3+ Bazı durumlarda thread'ler arasında veri aktarımı gerekebilir. ** Channel** enstrümanı farklı thread'ler arasında veri
4+ taşınması için kullanılır . Rust standart kütüphanesi varsayılan olarak ** Multi Producer - Single Consumer** türünü
5+ destekler. Farklı senaryolar için ** tokio** , ** crossbeam** gibi küfelerden de yararlanılabilir. ** MPSC** senaryosunda
6+ producer yani veri yayımını gerçekleştiren n sayıda iş parçacığı varken tek bir tüketici ya da dinleyici söz konusudur.
7+ Kanallar aşağıdaki örnek senaryolarda sıklıkla tercih edilir;
8+
9+ - Görev _ (task)_ sonuçlarının ana bir ** thread** içerisine toplanması
10+ - ** HTTP** isteklerinin paralel olarak işlenmesi
1111- Sistemde gerçekleşen olayların ana bir döngüye yönlendirilmesi
1212- GUI _ (Graphic User Interface)_ olaylarının merkezi bir yürütücüye aktarılması
1313- Okuma → işleme → yazma akışının parçalanarak thread’lere dağıtılması
1414- Merkezi log toplayıcı yapılar
1515
16- Kanallarda sahiplik _ (Ownership)_ kurallarına uygunluk vardır. Veri gönderildiğinde, alıcı taraf bunu recv() veya iter()
17- fonksiyonları ile alır. Sahiplik göndericiden devralınır. Asenkron ve senkron uyarlamaları yazmak mümkündür. ** Tokio **
18- veya ** async-std** gibi asenkron çalışma ortamları için defacto haline gelmiş olan ** tokio::sync::mpsc ** küfesi
19- kullanılır. Performans gereksinimi olan durumlarda ise ** crossbeam-channel** tercih edilebilir.
16+ Kanallarda sahiplik _ (Ownership)_ kurallarına uygunluk vardır. Veri gönderildiğinde, alıcı taraf bunu ** recv()** veya
17+ ** iter() ** fonksiyonları ile alır. Sahiplik göndericiden devralınır. Asenkron ve senkron uyarlamaları yazmak mümkündür.
18+ ** Tokio ** veya ** async-std** gibi asenkron çalışma ortamları için artık bir standart haline gelmiş olan ** tokio::sync::
19+ mpsc ** küfesi kullanılır. Performans gereksinimi olan durumlarda ise ** crossbeam-channel** tercih edilebilir.
2020
2121## Temel Kullanım
2222
23- Kanal kullanımını en basit haliyle aşağıdaki gibi ele alabiliriz .
23+ Kanal kullanımını en basit haliyle aşağıdaki gibi ele alınabilir .
2424
2525``` rust
2626use std :: sync :: mpsc :: channel;
@@ -43,13 +43,13 @@ pub fn hello_channels() {
4343}
4444```
4545
46- Bu örnekte spawn metodu ile açılan thread içerisinde message değişkeninin sahip olduğu veri ana thread'de receiver ile
47- yakalanır ve ekrana basılır. channel çağrısı generic Sender ve Receiver veri yapılarının generic nesne örneklerini
48- gönderir . Buna göre transmitter _ (yani Sender)_ nesnesini kullanarak bir thread içerisinde kanala mesaj gönderimi
49- sağlanabilir. Bu örnekte String türünden bir içerik gönderilmektedir. Receiver nesne örneğinin recv fonksiyonu ile de
50- kanala bırakılan mesaj yakalanmaktadır. recv fonksiyonu kanaldaki mesaj gelene kadar çalıştığı thread'i bekletir.
51- Örnekte dikkat edilmesi gereken noktalardan birisi de message değişkenini kanala gönderdikten sonra yeniden kullanmaya
52- çalışmaktır. Bu aşağıdaki hatanın oluşmasına sebebp olur.
46+ Bu örnekte ** spawn** metodu ile açılan ** thread** içerisinde ** message** değişkeninin sahip olduğu veri ana thread'de
47+ ** receiver ** ile yakalanır ve ekrana basılır. ** channel** çağrısı ** generic Sender** ve ** Receiver** veri yapılarının
48+ generic nesne örneklerini döndürür . Buna göre transmitter _ (yani Sender)_ nesnesini kullanarak bir thread içerisinde
49+ kanala mesaj gönderimi sağlanabilir. Bu örnekte ** String** türünden bir içerik gönderilmektedir. ** Receiver** nesne
50+ örneğinin ** recv ** fonksiyonu ile de kanala bırakılan mesaj yakalanmaktadır. ** recv** fonksiyonu kanaldaki mesaj gelene
51+ kadar çalıştığı thread'i bekletir. Örnekte dikkat edilmesi gereken noktalardan birisi de ** message** değişkenini kanala
52+ gönderdikten sonra yeniden kullanmaya çalışmaktır. Bu kullanım aşağıdaki hatanın oluşmasına sebebp olur.
5353
5454``` text
5555error[E0382]: borrow of moved value: `message`
@@ -68,11 +68,12 @@ error[E0382]: borrow of moved value: `message`
6868 |
6969```
7070
71- Tabii bu durumda copy trait'i ile beslenen türler için söz konusu olmaz zira ilgili veriler kanala kopyalanarak taşınır.
71+ Tabii bu durum ** copy** trait'i ile beslenen türler için söz konusu olmaz zira ilgili veriler kanala kopyalanarak
72+ taşınır.
7273
7374## Multi-Producer Kullanımı
7475
75- Aşağıdaki örnek kod parçasında ise birden fazla gönderici ele alınır .
76+ Aşağıdaki örnek kod parçasında ise birden fazla gönderici ele alınmaktadır .
7677
7778``` rust
7879use std :: sync :: mpsc :: channel;
@@ -106,15 +107,14 @@ pub fn multi_producer() {
106107}
107108```
108109
109- Bu örnekte 10 farklı ** thread** kanala mesaj bırakır. Thread'ler ** spawn** çağırısı ile ayağa kaldırılmadan önce *
110- * transmitter** nesnesinin bir klonunun oluşturulduğunda dikkat edilmelidir. Her bir ** thread** kendi ** transmitter**
111- klonunu kullanarak kanala mesaj bırakır. Mesajlar kanala senkron sırada bırakılır. İlerleyen satırlarda bir ** for**
112- döngüsü ile kanala gelen mesajların ** Receiver** nesnesi üzerinden yakalanması işlemi gerçekleştirilir. Dikkat edilmesi
113- gereken noktalardan birisi de ** drop** çağrısıdır. Açık bir şekilde ** transmitter** nesnesi açıkça ** drop** edilmiştir.
114- Bu yapılmadığı durumda receiver dan mesajlar dinlenmeye devam eder ve program sonlanmaz. Zire klonlanan receiver
115- örnekler halen daha yaşamaktadır. Bazı durumlarda zaten istenen bir durumdur. Sürekli dinlemede kalması gereken bir
116- receiver gerektiren senaryolar buna örnek verilebilir. Farklı bir örnekle devam edip otomatik kapanma durumunu ele
117- alalım.
110+ Senaryoda birbirinden bağımsız çalışan 10 farklı ** thread** aynı kanala mesaj bırakır. Thread'ler ** spawn** çağırısı ile
111+ ayağa kaldırılmadan önce ** transmitter** nesnesinin bir klonunun oluşturulduğunda dikkat edilmelidir. Her bir ** thread**
112+ kendi ** transmitter** klonunu kullanarak kanala mesaj bırakır. Mesajlar kanala senkron sırada bırakılır. İlerleyen
113+ satırlarda bir ** for** döngüsü ile kanala gelen mesajların ** Receiver** nesnesi aracılığıyla yakalanması sağlanır.
114+ Dikkat edilmesi gereken noktalardan birisi de ** drop** çağrısıdır. Açık bir şekilde ** transmitter** nesnesi ** drop**
115+ edilmiştir. Bu yapılmadığı takdirde ** receiver** ' dan mesajlar dinlenmeye devam eder ve program sonlanmaz. Zira
116+ klonlanan receiver örnekleri halen daha aktiftir. Bazı senaryolarda bu zaten istenen bir durumdur. Farklı bir örnekle
117+ devam edip otomatik kapanma durumunu ele alalım.
118118
119119``` rust
120120use std :: sync :: mpsc :: channel;
@@ -148,16 +148,17 @@ pub fn multi_producer() {
148148}
149149```
150150
151- Bu örnekte transmitter ve transmitter_clone nesneleri tanımlandıkları thread'ler sonlandığında düşürülürler ve
152- dolayısıyla receiver üzerinden yakalanacak kanal mesajlarının sayısı bellidir. Dolayısıyla program beklendiği şekilde
153- tüm kanal mesajları işlendikten sonra sonlanır.
151+ Bu örnekte ** transmitter** ve ** transmitter_clone** nesneleri tanımlandıkları iş parçacıkları sonlandığında bellekten
152+ düşürülür ve dolayısıyla ** receiver** üzerinden yakalanacak kanal mesajlarının sayısı bellidir. Dolayısıyla program
153+ beklendiği şekilde tüm kanal mesajları işlendikten sonra sonlanır.
154154
155155## Örnek Senaryo
156156
157157Kanal kullanımları ile ilgili örnek bir senaryo ele alalım. Bu senaryoda sistemdeki n sayıda rapor dosyasının n thread
158- ile işlenmesi söz konusudur. Her bir thread ele aldığı dosyayı işledikten sonra kanal üzerine bilgi bırakır. En sonunda
159- tüm bu bilgiler receiver üzerinden toplanır. İlk versiyonda standart kütüphanenin Sender ve Receiver yapıları
160- kullanılmaktadır.
158+ ile işlenmesi söz konusudur. Her bir ** thread** ele aldığı dosyayı işledikten sonra kanala bir bilgi bırakır. Bir gerçek
159+ hayat senaryosunda işlem sonucu, raporun ayrı bir formata çevrilmesi, farklı ağlardaki servislere gönderilmesi,
160+ parçalanarak efektif şekilde işlenmesi gibi süreçler işletilebilir. En sonunda tüm bu bilgiler receiver üzerinden
161+ toplanır. İlk versiyonda standart kütüphanedeki ** Sender** ve ** Receiver** yapıları kullanılmaktadır.
161162
162163``` rust
163164use std :: sync :: mpsc :: channel;
@@ -189,7 +190,7 @@ pub fn process_reports() {
189190 . send (format! (" Processing '{}' report..." , report ))
190191 . unwrap ();
191192
192- // Rapor dosyalarının işlendiği bazı business'lar çağırdığımızı düşünelim
193+ // Rapor dosyalarının işlendiği bazı süreçlerin işletildiğini düşünelim
193194
194195 thread :: sleep (Duration :: from_secs (sleep_time ));
195196
@@ -211,16 +212,17 @@ pub fn process_reports() {
211212}
212213```
213214
214- Her dosya sıralı bir şekilde döngüye girer ve herbirisi için ayrı bir ** thread** açılır. Bu thread'lerde dosyalar ile
215+ Her dosya sıralı şekilde döngüye girer ve herbirisi için ayrı bir ** thread** açılır. Bu thread'lerde dosyalar ile
215216ilgili farklı iş süreçlerinin işletildiğini düşünebiliriz. Dosya işleyişlerinin farklı sürelerde gerçekleştiğini simüle
216- etmek için rand kütüphanesi ile üretilen rastgele değerlerde beklemeler yapılmaktadır .
217+ etmek için ** rand** küfesi ile üretilen rastgele sürelerde duraksatmalar yapılır .
217218
218219## Asenkronluk
219220
220- Rust'ın MPSC modülü aslında gerçek anlamda bir asenkronluk sağlamaz. Bir başka deyişle Sender'dan mesajlar asenkron
221- olarak ilerletilebilse de Receiver tarafı bunları senkron olarak işler. Tam bir asenkron çalışma sağlayabilmek için
222- yardımcı küfelerden _ (crates)_ yararlanılabilir. Aşağıdaki ilk senaryoda ana thread'in bloklanmasına neden olan bir
223- döngü kullanımı söz konusudur.
221+ Rust'ın ** MPSC** modülü aslında gerçek anlamda bir asenkronluk sağlamaz. ** Sender** nesnesi üzerinden iletilen mesajlar
222+ asenkron olarak yönlendirilse de ** Receiver** tarafı bunları senkron olarak işler. Tam bir asenkron çalışma
223+ sağlayabilmek için yardımcı küfelerden _ (crates)_ yararlanılabilir. Aşağıdaki ilk senaryoda ana iş parçacığının
224+ bloklanmasına neden olacak şekilde kasıtlı bir döngü kullanımı söz konusudur. Döngünün on defa işleyişini tamamlaması
225+ gerekir.
224226
225227``` rust
226228use std :: sync :: mpsc :: channel;
@@ -246,7 +248,7 @@ pub fn do_with_standard() {
246248
247249 println! (" Waiting for all tasks..." );
248250
249- // Aşağıdaki döngü main thread üzerine çalışıp buradaki akışı bloklamaya neden olacak
251+ // Aşağıdaki döngü main thread içerisinde çalışıp akışı bloklamaya neden olur
250252 for i in 0 .. 10 {
251253 thread :: sleep (Duration :: from_secs (1 ));
252254 println! (" Main task is working...Counting {}" , i );
@@ -262,9 +264,9 @@ pub fn do_with_standard() {
262264
263265![ Runtime] ( Runtime.png )
264266
265- Aynı örneği ** tokio** küfesini kullanarak ele aldığımızda ise ana thread'in bloklanmadan for döngüsünün işletildiğini
266- görebiliriz. Bu receiver tarafında mesajların asenkron ele alınabildiğinin de ispatıdır. tokio küfesini kullanmak için *
267- * Full feature** seti ile eklenmesi gerekmektedir.
267+ Aynı örneği ** tokio** küfesini kullanarak ele alalım. Bu sefer ana ** thread** 'i bloklayan for döngüsünü de asenkron bir
268+ task olarak başlatalım. Buna göre receiver tarafının ilgili mesajları asenkron olarak yakalaması beklenir. ** tokio* *
269+ küfesini kullanmak için projeye * * Full feature** seti ile eklenmesi gerekmektedir.
268270
269271``` bash
270272 cargo add tokio -F full
0 commit comments