🚀 BAŞTAN SONA RUST DİLİ BÖLÜM-17: Async / Await ve Tokio Runtime ⚡

Konu Özeti

Rust'ta asenkron programlamanın temelleri, OS thread'lerine kıyasla avantajları ve cooperative multitasking mantığı açıklanıyor. Future trait'i, polling mekanizması, async/await sözdizimi ve Tokio runtime'ın kurulumu ile kullanımı örneklerle gösteriliyor. Ayrıca tokio::spawn ile görev oluşturma, tokio::join! ile eşzamanlı çalıştırma ve asenkron TCP sunucusu uygulaması yer alıyor.

🚀 BAŞTAN SONA RUST DİLİ BÖLÜM-17: Async / Await ve Tokio Runtime ⚡

Selamlar! Serimizin 17. bölümüne hoş geldiniz.

Önceki bölümde `thread::spawn`, `mpsc` kanalları ve `Arc<Mutex<T>>` ile multithreaded (çok iş parçacıklı) paralel programlamayı incelemiştik. Bu bölümde ise yüksek performanslı ağ servislerinin, web sunucularının ve I/O odaklı uygulamaların temeli olan **Asenkron Programlama (Async / Await)** konusunu ele alacağız.

---

📌 1. Thread vs Async: Neden Asenkron Programlama? 🤔

• İşletim Sistemi Thread'leri (OS Threads):
- Her bir Thread için işletim sistemi bellek (stack) ayırır ve bağlam geçişi (context switch) maliyeti vardır.
- Binlerce OS Thread'i açmak bellek ve CPU tüketimini hızla artırır.

• Asenkron (Async) Programlama:
- Tek bir Thread üzerinde veya az sayıda Thread ile binlerce eşzamanlı görevi (Task) çalıştırabilir.
- Bir görev I/O işlemi (dosya okuma, ağ isteği, veritabanı sorgusu) beklerken CPU boşta durmaz; diğer göreve geçer.
- Bu yapıya **Cooperative Multitasking** denir.

---

🔮 2. `Future` Trait'i ve Polling Mantığı 🔄

Rust'ta asenkron bloklar veya fonksiyonlar geriye bir **`Future`** döndürür.

`Future`, gelecekte tamamlanacak bir değeri temsil eden bir durum makinesidir (state machine).

pub trait Future {
type Output;
fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output>;
}

pub enum Poll<T> {
Ready(T), // İşlem bitti, veri hazır!
Pending, // İşlem devam ediyor, henüz hazır değil.
}

⚠️ **En Önemli Kural:** Rust'ta Future'lar **LAZY (Tembel)** çalışır! Bir `async` fonksiyonu çağırmak o fonksiyonu çalıştırmaz; sadece bir `Future` nesnesi döndürür. O `Future`'ın çalışması için bir **Async Runtime** tarafından yürütülmesi ve üzerine `.await` atılması gerekir.

---

🚀 3. Tokio Runtime ve `Cargo.toml` Kurulumu 🛠️

Rust dilinin çekirdeğinde varsayılan bir asenkron yürütücü (runtime) YOKTUR. Topluluk tarafından geliştirilen en popüler ve endüstri standardı runtime **`Tokio`**'dur.

Bir Tokio projesi başlatmak için `Cargo.toml` dosyasına şu bağımlılık eklenir:

[dependencies]
tokio = { version = "1.0", features = ["full"] }

---

✍️ 4. `async fn`, `.await` ve `#[tokio::main]` 🎯

Asenkron bir fonksiyon tanımlamak için `async fn` yazılır. Bu fonksiyonun sonucunu beklemek için `.await` ifadesi kullanılır.

`.await` kullanımı yalnızca `async` bloklar veya `async fn` içinde geçerlidir!

use std::time::Duration;
use tokio::time::sleep;

async fn veri_getir() -> String {
// thread::sleep yerine asenkron sleep kullanılır (Thread'i bloklamaz!)
sleep(Duration::from_secs(2)).await;
String::from("Ağdan veri çekildi!")
}

#[tokio::main] // Tokio Runtime'ı başlatır ve main'i asenkron yapar
async fn main() {
println!("Veri isteniyor...");

let sonuc = veri_getir().await; // İşlem bitene kadar asenkron olarak bekler

println!("Sonuç: {}", sonuc);
}

---

🔀 5. Eşzamanlı Görevler: `tokio::spawn` ve `tokio::join!` 🏎️

Birden fazla asenkron görevi aynı anda paralel/eşzamanlı çalıştırmak için iki ana yöntem vardır:

### A. `tokio::spawn` (Arka Planda Görev Başlatma)
Görevleri Tokio'nun yönettiği thread havuzuna atar. Dönüş değeri bir `JoinHandle`'dır.

use tokio::time::{sleep, Duration};

async fn gorev(id: u32, saniye: u64) {
sleep(Duration::from_secs(saniye)).await;
println!("Görev {} tamamlandı!", id);
}

#[tokio::main]
async fn main() {
let handle1 = tokio::spawn(gorev(1, 2));
let handle2 = tokio::spawn(gorev(2, 1));

// İki görev aynı anda arka planda çalışıyor!
handle1.await.unwrap();
handle2.await.unwrap();
}

### B. `tokio::join!` (Birden Fazla Future'ı Aynı Anda Bekleme)
Tüm Future'ların aynı anda çalışmasını sağlar ve hepsi bitene kadar bekler.

use tokio::time::{sleep, Duration};

async fn indir_a() -> &'static str {
sleep(Duration::from_secs(2)).await;
"A Verisi"
}

async fn indir_b() -> &'static str {
sleep(Duration::from_secs(1)).await;
"B Verisi"
}

#[tokio::main]
async fn main() {
// İki indirme işlemi eşzamanlı başlar. Toplam süre 3sn değil, en uzunu olan 2sn sürer!
let (res_a, res_b) = tokio::join!(indir_a(), indir_b());

println!("Sonuçlar: {} ve {}", res_a, res_b);
}

---

🌐 6. Pratik Örnek: Asenkron TCP Sunucusu 🔌

Tokio ile basit bir Echo Server (Gelen metni geri gönderen sunucu) yazalım:

use tokio::net::TcpListener;
use tokio:🇮🇴:{AsyncReadExt, AsyncWriteExt};

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let listener = TcpListener::bind("127.0.0.1:8080").await?;
println!("TCP Sunucu 8080 portunda dinleniyor...");

loop {
// Yeni bir bağlantı geldiğinde kabul et
let (mut socket, adres) = listener.accept().await?;
println!("Yeni bağlantı: {}", adres);

// Her istemci için ayrı bir asenkron görev başlat
tokio::spawn(async move {
let mut buf = [0; 1024];

loop {
let n = match socket.read(&mut buf).await {
Ok(n) if n == 0 => return, // Bağlantı kapandı
Ok(n) => n,
Err(_) => return,
};

if socket.write_all(&buf[0..n]).await.is_err() {
return;
}
}
});
}
}

---

📝 Bölüm Özeti ve Gelecek Bölüm 🔮

Bu bölümde Async/Await mantığını, `Future` yapısını, `Tokio` runtime kullanımını, `tokio::spawn` ve `tokio::join!` ile eşzamanlı görev yönetimini öğrendik.

👉 Bölüm 18'de Bizi Ne Bekliyor?
• Makro Sistemi (Macros): `macro_rules!` ve Declarative Macros 🧙‍♂️
• Procedural Macros (Derleme Zama
nı Kod Üretimi)
• Custom Derive, Attribute Macros ve Function-like Macros

Sorularınızı konu altından iletebilirsiniz. Serimizin bir sonraki bölümünde görüşmek üzere! 🦀✨

🔒 Bu içeriği görmek için giriş yapın

 
Yanıt yazmak için giriş yapmalısınız
Forum özelliklerini kullanmak ve Level 2 üyelik satın almak için hesabınıza giriş yapın.
135,050Konular
3,297,703Mesajlar
326,233Kullanıcılar
membiSon Üye
Üst Alt