Skip to content

Commit c4f51ea

Browse files
committed
Updated readme document.
1 parent 9f4872f commit c4f51ea

File tree

1 file changed

+50
-48
lines changed

1 file changed

+50
-48
lines changed

Lesson_12/README.md

Lines changed: 50 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -1,26 +1,26 @@
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
2626
use 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
5555
error[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
7879
use 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
120120
use 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

157157
Kanal 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
163164
use 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
215216
ilgili 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
226228
use 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

Comments
 (0)