|
| 1 | +# Ders 14: Asenkron Programlama |
| 2 | + |
| 3 | +Rust eşzamanlı _(concurrent)_ programlama haricinde asenkron programlamayı da destekler. Asenkron programlama özellikle |
| 4 | +dosya I/O işlemleri, network operasyonları, zaman bazlı görevler _(scheduled tasks)_ ve servis iletişimi gibi beklemeye |
| 5 | +neden olan süreçlerde CPU'nun idle kalmak yerine bahsedilen operasyonları icra etmesi için kullanılan bir yaklaşımdır. |
| 6 | +Rust bu ihtiyaca async ve await anahtar kelimeleri ile cevap verir. Rust tarafında asenkron programlama süreçleri |
| 7 | +genellikle defacto hale gelmiş çeşitli küfeler _(crates)_ ile sağlanır. Tokio küfesi bunlar arasında en popüler |
| 8 | +olanlarındandır. Bunun sebebi async fn çağrıları sonucu dönen Future nesnelerini yönetecek hazır bir ortamın built-in |
| 9 | +olarak gelmemesidir. |
| 10 | + |
| 11 | +## Thread vs Async/Await |
| 12 | + |
| 13 | +Thread ve async/await kullanımları sıklıkla birbirlerine karıştırılır. Her iki enstrüman arasındaki farklılıklar |
| 14 | +aşağıdaki tabloda özetlenmiştir. |
| 15 | + |
| 16 | +| **Kriter** | **Thread** | **Async/Await** | |
| 17 | +|-----------------------|----------------------------------------------------------------------------------------------------------------------------------------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------| |
| 18 | +| **Paralellik** | Gerçek paralell çalışma ortamı söz konusudur _(çok çekirdek desteği)_ | Genellikle tek thread üzerinde iş birliği ile çalışır _(Bu bir çalışma zamanı da gerektirir, async-std, tokio gibi)_ | |
| 19 | +| **Kaynak Kullanımı** | Ağır _(her thread kendi stack alanını taşır ve bu varsayılan olarak 2Mbtır)_ Thread'ler Idle durumdayken bile enerji sarf ettirir. | Hafif _(runtime tarafından yönetilen task' lar söz konusudur)_ | |
| 20 | +| **Bloklama** | I/O seviyesinde bloklamalar varsa tüm thread'ler etkilenir. | I/O bloklama diğer görevleri etkilemez. | |
| 21 | +| **Ölçeklenebilirlik** | Thread sayısı fiziksel sınırlamalara bağlıdır _(Çekirdek sayısı gibi)_ Çok fazla thread açılması sistemde aşırı yüklenmelere neden olabilir. | Binlerce asenkron görev oluşturulabilir. | |
| 22 | +| **Kod Karmaşıklığı** | Göreceli bir durumdur, nispeten basittir. | Hata ve bağımlılıkların yönetimi karmaşık olabilir. | |
| 23 | +| **Senaryolar** | İşlemci yoğun/öncelikli işler için uygundur. | Daha çok I/O yoğun işler için uygundur. | |
| 24 | +| **Ne zaman?** | CPU yoğun işlerde _(Ağır matematiksel hesaplamalar)_, her görevin tam bağımsız ve paralel çalışması gerektiği durumlar | Web istekleri, dosya erişimleri gibi I/O yoğun işler, yüksek ölçeklenebilirlik gerektiren hafif işler, enerji ve kaynak tasarrufunun önemli olduğu durumlar | |
| 25 | + |
| 26 | +## Örnekler |
| 27 | + |
| 28 | +Asenkron programlama konseptini anlamanın en iyi yolu gerçek hayat örnekleri üzerinden ilerlemektir. Bir sunucudaki |
| 29 | +işlemci, bellek ve disk kullanım durumlarını anlık olarak takip eden bir sistem programı geliştirmek istediğimizi |
| 30 | +düşünelim. Burada donanım bazında çalışan fonksiyonellikler olduğunu ifade edebiliriz. Senkron bir okuma yerine asenkron |
| 31 | +olarak bu değerlerin okunması sağlanabilir. Aşağıdaki örnek kod parçasında bu durumu tokio küfesi kullanılarak simüle |
| 32 | +edilmektedir. |
| 33 | + |
| 34 | +```rust |
| 35 | +use rand::Rng; |
| 36 | +use std::time::Duration; |
| 37 | +use tokio::sync::mpsc; |
| 38 | +use tokio::task; |
| 39 | +use tokio::time::sleep; |
| 40 | +#[tokio::main] |
| 41 | +async fn main() { |
| 42 | + let (log_transmitter, mut log_receiver) = mpsc::channel(100); |
| 43 | + |
| 44 | + let cpu_task = task::spawn(fetch_metrics("CPU Service", log_transmitter.clone())); |
| 45 | + let memory_task = task::spawn(fetch_metrics("Memory Service", log_transmitter.clone())); |
| 46 | + let disk_task = task::spawn(fetch_metrics("Disk Service", log_transmitter)); |
| 47 | + |
| 48 | + let logger_task = task::spawn(async move { |
| 49 | + while let Some(metric) = log_receiver.recv().await { |
| 50 | + println!("LOG: {}", metric); |
| 51 | + } |
| 52 | + }); |
| 53 | + |
| 54 | + let _ = tokio::join!(cpu_task, memory_task, disk_task, logger_task); |
| 55 | +} |
| 56 | + |
| 57 | +async fn fetch_metrics(service_name: &str, tx: mpsc::Sender<String>) { |
| 58 | + let interval = Duration::from_secs(5); |
| 59 | + for i in 1..=10 { |
| 60 | + let metric = format!("{} - Metric {}: {}", service_name, i, get_metric()); |
| 61 | + if tx.send(metric).await.is_err() { |
| 62 | + println!("{}: Channel isn't active!", service_name); |
| 63 | + break; |
| 64 | + } |
| 65 | + sleep(interval).await; |
| 66 | + } |
| 67 | +} |
| 68 | + |
| 69 | +fn get_metric() -> f64 { |
| 70 | + let mut rng = rand::rng(); |
| 71 | + rng.random_range(50.0..100.0) |
| 72 | +} |
| 73 | +``` |
| 74 | + |
| 75 | +Örnek kod sembolik olarak işlemci, bellek ve disk kullanım oranlarını takip eden fonksiyonellikleri ele alır. |
| 76 | +fetch_metrics metodu asenkron olarak çağırabilen bir fonksiyondur. async keyword bu nedenle kullanılmıştır. Sistemde log |
| 77 | +mesajlarının üretimi ve yakalanması bir kanal üzerinden gerçekleştirilir. Örnekte dikkat edileceği üzere tokio küfesi |
| 78 | +kullanılmıştır. Main metodu da async keyword ile imzalanmıştır. Program beş saniyede bir işlemci, bellek ve disk |
| 79 | +kullanımları ile ilgili bilgi alıp ekrana yazdırır. |
| 80 | + |
| 81 | +// YENİ ÖRNEKLER EKLENECEK |
0 commit comments