CodeBlanks Logo Icon CodeBlanks

Future traiti

Future trait'inin poll mekanizmasını öğrenirsin.

Future trait'i

async fn'in arkasında tek metotlu bir trait vardır:

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

pub enum Poll<T> {
    Ready(T),
    Pending,
}

poll ya sonucu (Ready) döndürür ya da henüz hazır olmadığını (Pending) söyler. Pending dönen Future, hazır olduğunda cx.waker() ile yürütücüyü uyandırmayı taahhüt eder.

El yazımı Future

Birkaç kez Pending dönüp sonra hazır olan bir Future:

struct Geri {
    kalan: u32,
}

impl Future for Geri {
    type Output = &'static str;
    fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
        if self.kalan == 0 {
            return Poll::Ready("bitti");
        }
        self.kalan -= 1;
        cx.waker().wake_by_ref();   // "beni tekrar poll et"
        Poll::Pending
    }
}

Geri alanları Unpin olduğu için Pin<&mut Self> üzerinden alanlara doğrudan erişilebilir.

Uygulama Sayan yürütücü

Yukarıdaki Geri Future'ını yaz. block_on'u, sonucu ve kaç kez poll ettiğini birlikte döndüren calistir olarak değiştir. Geri { kalan: 3 } için ikisini boşlukla yazdır.

Başlangıç kodu

main.rs
use std::future::Future;
use std::pin::{pin, Pin};
use std::task::{Context, Poll, Waker};

fn main() {
    // buraya yaz
}

Örnek çözüm

main.rs
use std::future::Future;
use std::pin::{pin, Pin};
use std::task::{Context, Poll, Waker};

struct Geri {
    kalan: u32,
}

impl Future for Geri {
    type Output = &'static str;
    fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
        if self.kalan == 0 {
            return Poll::Ready("bitti");
        }
        self.kalan -= 1;
        cx.waker().wake_by_ref();
        Poll::Pending
    }
}

fn calistir<F: Future>(f: F) -> (F::Output, u32) {
    let mut f = pin!(f);
    let mut cx = Context::from_waker(Waker::noop());
    let mut sayi = 0;
    loop {
        sayi += 1;
        if let Poll::Ready(v) = f.as_mut().poll(&mut cx) {
            return (v, sayi);
        }
    }
}

fn main() {
    let (sonuc, n) = calistir(Geri { kalan: 3 });
    println!("{} {}", sonuc, n);
}

Beklenen çıktı

bitti 4

Soru ve cevaplar

Dersin sorularını cevaplarıyla birlikte inceleyebilirsin. Kendini denemek istersen dersi interaktif olarak çöz.

1 Bir Future <code>Pending</code> döndürüp Waker'ı hiç çağırmazsa gerçek bir runtime'da ne olur?

  • Runtime yeniden dener
  • Panic
  • Sonuç None olur
  • Görev bir daha poll edilmez ve sonsuza dek takılır Doğru cevap

Açıklama: Uyandırma sözleşmesi zorunludur; kendi Future'ını yazarken en sık yapılan hata budur.

2 Henüz hazır değil

Soru
self.kalan -= 1;
cx.waker().wake_by_ref();
Poll::____
Cevap
self.kalan -= 1;
cx.waker().wake_by_ref();
Poll::Pending

Açıklama: Pending, sonucun henüz hazır olmadığını bildirir.

3 Öğe ve görevi

Kavram Anlamı
Poll::Ready(v) Sonuç hazır
Poll::Pending Daha sonra
cx.waker() Uyandırıcı
type Output Sonuç türü

İleri seviye bölümündeki tüm dersler