-
Sadrazamv4
instagram:sadrazam.spy Tg:Sadrazamv4
🚀 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:
uration;
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! 🦀✨
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:
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