ProgramlamaSistem Programcısı

Rust'ta asenkronluk ve Future ile çalışma nasıl yapılandırılmıştır? async/await'in uygulanmasındaki benzersiz özellikler nelerdir ve bu, diğer dillerdeki benzer mekanizmalardan nasıl farklıdır?

Hintsage yapay zeka asistanı ile mülakatları geçin

Cevap

Rust'taki asenkronluk, gelecekte sonuçlanacak bir işi temsil eden Future nesnesi aracılığıyla gerçekleştirilir. async fn ile tanımlanan fonksiyonlar, Future trait'ini uygulayan anonim bir yapı-jeneratörü döner. Asenkron kodu çalıştırmak için bir runtime (örneğin, Tokio veya async-std) kullanılır, çünkü standart kütüphane yerleşik bir event loop içermez.

Rust'ın ana özellikleri:

  • Sıfır maliyetli soyutlamalar — derleyici, async kodu durum makinesine dönüştürür; eğer görev izin verirse, yığın tahsisi olmadan.
  • Yerel garbage collector olmaması — tüm kaynaklar açıkça yönetilir ve bu, yaşam süresi ve sahiplik konularında özel bir dikkat gerektirir.
  • Send/Sync — görevlerin iş parçaları arasındaki taşınabilirlik ve senkronizasyon kısıtlamaları.

Örnek:

use tokio::time::sleep; use std::time::Duration; async fn foo() { println!("Merhaba"); sleep(Duration::from_secs(1)).await; println!("Dünya!"); } #[tokio::main] async fn main() { foo().await; }

Kandırmaca Soru

Rust'ta asenkron bir fonksiyon varsayılan olarak çağrıldığında hemen çalışabilir mi? Neden?

Cevap: Hayır. async fn çağrısı, bir sonuç değil, bir Future (durum makinesi) türünde nesne döner. Gerçek bir yürütme için .await çağrılmalı veya Future bir runtime'a verilmelidir. Çağrı yalnızca görevin tanımını oluşturur, ancak onu yürütmez.

Örnek:

async fn answer() -> u32 { 42 } let fut = answer(); // burada bir yürütme yok, sadece future oluşturuluyor let result = fut.await; // yürütme burada başlıyor

Konunun incelikleri yüzünden gerçek hata örnekleri


Hikaye

Highload backend projesinde bir junior geliştirici birkaç async fonksiyonu tanımladı, ancak hiçbir yerde .await çağrısı yapmadı. Bu nedenle ana iş parçaları senkron olarak çalıştı ve bu da performans düşüşüne ve yanıt süresinde 3 kat artışa yol açtı.

Hikaye

Bir mikroserviste async api kullanıyorduk ve tokio ile etkileşim kuruyorduk. Geçiş sırasında geliştirici, async-std ve tokio'yu aynı anda kullanmaya çalıştı ve event loop'un yalnızca bir tane olması gerektiğini unuttu. Sonuç olarak, her iki runtime da çakıştığı için donmalara ve runtime paniklerine neden oldu.

Hikaye

Takımın bir üyesi, Future içinde kullanılan türler için Send/Sync kısıtlamalarını unuttu. İş parçaları arasında future paylaşmaya çalıştığında uygulama, belirli bir yapı için Send'i uygulama gerektiren bir derleme hatası ile çöktü. Bu, durum depolama mimarisinin yeniden gözden geçirilmesini gerektirdi.