---
title: 'Gelecekler (futures)'
source: 'https://academia.sh/tr/kurslar/rust-eszamanlilik/gelecekler'
course: 'Eşzamanlılık ve Asenkron Rust'
language: tr
updated: '2026-09-13T05:09:28+00:00'
license: 'CC BY-SA 4.0'
objectives:
    - 'Bir geleceğin kurulmasının onu ilerletmediğini, yalnız yoklandığında ilerlediğini gösterir'
    - 'Aynı kaynaktan kurulan iki görevi yürütücüye vererek ve vermeyerek yoklanınca ile hiç sınıflarını ayırt eder'
    - 'Bu kursun sorduğu "ilerlemek için neye ihtiyaç var" sorusunun bir gövdenin kaç kez koştuğunu sayan sorudan farkını açıklar'
---

# Gelecekler (futures)

Bir gelecek, kurulduğu anda değil yalnız yoklandığında ilerleyen tembel bir değerdir: aynı kaynaktan kurulan iki görevden yürütücüye verilen bir kaydı deftere yazarken, verilmeyen hiçbir iz bırakmaz.

İş Parçacıkları konusu paylaşılan durumu bir kilitle ya da atomik bir işlemle koruyan iş
parçacıklarını ölçtü; ikisinde de birim bir kez başlatıldıktan sonra ya kendi başına
ilerliyordu ya da bir başkasının bitmesini bekliyordu. Bu konu aynı soruyu — bir iş ilerlemek
için neye ihtiyaç duyuyor — başka bir birime taşıyor: eşzamansız görev. İlk bakışta yanıt
tanıdık görünüyor, kendi başına ya da başkası bitince. Ama Rust'ın eşzamansız modeli üçüncü
bir olasılığı gündeme getiriyor ve bu ders tam olarak onu kuruyor: bir görev, kaynakta
yazılmış olmasına rağmen hiç ilerlemeyebilir.

Bir iş parçacığı, işletim sisteminin ayırdığı bir yürütme birimidir: `thread::spawn`
çağrıldığı anda kendi yığıtı ve zamanlanma hakkı olan bir şey doğar, çağıran kod bir daha
elini sürmese bile ilerlemeye devam eder. Bir eşzamansız görev bunun tam tersi bir şeyi
temsil ediyor — kendi başına hiçbir yürütme bağlamı taşımayan, salt bir veri değeri. Bir
`HemenHazir` örneği kurulduğunda ne bir yığıt ayrılıyor ne de bir zamanlanma hakkı doğuyor;
ortada yalnız birkaç alan taşıyan sıradan bir yapı örneği var. Bu farkı görmek, kursun geri
kalanı için belirleyici: iş parçacıkları konusu ilerlemeyi işletim sisteminin bir kararı
olarak ölçtü, bu konu ilerlemeyi **kaynaktaki bir kod parçasının kararı** olarak ölçüyor.

Rust'ta bir eşzamansız görev, standart kitaplığın `Future` trait'ini gerçekleştiren bir
değerdir. Bu trait tek bir zorunlu yöntem bildirir: `poll`. Yöntem bir kez çağrıldığında iki
şeyden birini döndürür — görev bitmişse taşıdığı değeri saran `Ready`, bitmemişse `Pending`.
`Future` trait'i kavram olarak Rust'a özgü değil; farkı, bu kararı **kimin verdiğidir**.
Değeri üreten kod kendi kendine ilerlemez, ilerlemesi için dışarıdan bir çağrının `poll`u
tetiklemesi gerekir. Bu çağrıyı yapan bileşene **yürütücü** denir ve bu konunun üçüncü dersi
doğrudan ona ayrılmıştır; burada yürütücü yalnız görevi ilerletmek için gereken bir araç
olarak kullanılıyor, kendisi bu dersin konusu değil.

Bu tembellik rastgele bir gerçekleştirim ayrıntısı değil, `Future` trait'inin tasarımının
merkezinde duran bir karardır. Programlama Temelleri kursunda tanıtılan tembel değerlendirme
kavramı, bir ifadenin değerinin yalnız gerçekten ihtiyaç duyulduğunda hesaplanmasını
anlatıyordu; Rust'ın gelecekleri aynı ilkeyi eşzamansız işe uyguluyor. Bir gelecek kurmak
yalnız bir **tarif** yazmaktır — hangi adımların hangi sırayla atılacağının bir kaydı. Bu
tarifin gerçekten yürütülmesi, ayrı ve açık bir kararla, yürütücüye teslim edilerek başlıyor.
Ayrım önemli çünkü aksi halde çok sayıda geleceği aynı anda kurmak bile pahalı olurdu: her
biri kurulduğu anda çalışmaya başlasaydı, hangi görevin öncelikli olduğuna karar vermeden
önce hepsi zaten yarı yolda olurdu. Tembellik, kurma ile çalıştırma arasına bir ayrım
koyuyor; bu ayrım kursun kapanış dersinde bırakılan bir görevin bir daha hiç yoklanmamasının
neden mümkün olduğunu da açıklıyor — kaynakta durup hiç ilerlememiş bir gelecek, zaten bu
dersteki `_hic_yoklanmayan` ile aynı durumda.

## Bir Değerin Kurulması Onu İlerletmez

`Future` gerçekleştiren bir tipin örneğini kurmak, sıradan bir yapı örneği kurmaktan farklı
görünmüyor: alanlar dolduruluyor, değer bir değişkene bağlanıyor. Fark, bu kurulma anında
hiçbir şeyin **çalışmamasıdır**. Aşağıdaki kesit, hazır olduğunda hemen tamamlanan en yalın
gelecek türünü ve onu ilerletmek için gereken en yalın yürütücüyü tanımlıyor.

```rust
// ilerle.rs — cekirdegin kesiti: elle yazilan yurutucu ve hemen hazir olan bir gelecek.

use std::future::Future;
use std::pin::Pin;
use std::sync::mpsc::Sender;
use std::sync::{Arc, Condvar, Mutex};
use std::task::{Context, Poll, Wake, Waker};

pub struct Uyandirici {
    pub hazir: Mutex<bool>,
    pub kosul: Condvar,
}

impl Wake for Uyandirici {
    fn wake(self: Arc<Self>) {
        *self.hazir.lock().unwrap() = true;
        self.kosul.notify_one();
    }
}

pub fn kostur<F: Future>(gorev: F) -> (F::Output, u32) {
    let mut gorev = Box::pin(gorev);
    let u = Arc::new(Uyandirici {
        hazir: Mutex::new(false),
        kosul: Condvar::new(),
    });
    let waker: Waker = u.clone().into();
    let mut baglam = Context::from_waker(&waker);
    let mut yoklama = 0;
    loop {
        yoklama += 1;
        match gorev.as_mut().poll(&mut baglam) {
            Poll::Ready(x) => return (x, yoklama),
            Poll::Pending => {
                let mut h = u.hazir.lock().unwrap();
                while !*h {
                    h = u.kosul.wait(h).unwrap();
                }
                *h = false;
            }
        }
    }
}

pub struct HemenHazir {
    pub ad: &'static str,
    pub kanal: Sender<String>,
}

impl Future for HemenHazir {
    type Output = &'static str;
    fn poll(self: Pin<&mut Self>, _cx: &mut Context<'_>) -> Poll<&'static str> {
        self.kanal.send(self.ad.to_string()).unwrap();
        Poll::Ready(self.ad)
    }
}
```

`kostur` işlevi, Rust'ın standart kitaplığında bulunmayan bir parçayı elle kuruyor: bir
`Waker`, bir `Context` ve `poll`u tekrar tekrar çağıran bir döngü. Yürütücünün gövdesi bu
derste yalnız bir araç olarak veriliyor; asıl ölçülen, `HemenHazir` tipinin kendisi. `poll`
çağrılmadan önce bu tipin örneği bellekte duran sıradan bir değerden farksız — hiçbir alanı
çalışmıyor, hiçbir kanala bir şey göndermiyor. Yalnız `poll` çağrıldığında `kanal.send`
tetikleniyor ve değer üretiliyor.

`kostur`un döngüsü üç adımı tekrarlıyor: yoklama sayacını artırmak, `poll`u çağırmak, sonucu
değerlendirmek. `Ready` dönerse döngü biter ve değerle birlikte toplam yoklama sayısı geri
veriliyor. `Pending` dönerse döngü, `Uyandirici`nin taşıdığı mantıksal bayrağı `false`
bulduğu sürece bir koşul değişkeninde bekliyor — bu, iş parçacığını meşgul bir döngüde
döndürmek yerine gerçekten uyutan, Muteks ve Okuma/Yazma Kilidi dersinde tanıtılan kilitleme
ilkelleriyle aynı ailenin bir üyesi. `while` döngüsü tek bir `if` yerine kullanılıyor çünkü bir
koşul değişkeni kendisine hiç uyandırma çağrısı gelmeden de uyanabilir; bayrağı tekrar kontrol
etmek bu olası yanlış uyanışı görmezden geliyor. `Waker`, bir `Arc<Uyandirici>`nin kopyası
olarak taşınıyor — bir görev tek bir koşumda birden fazla kez `Pending` dönebildiği için, aynı
`Uyandirici` birden fazla `poll` çağrısı arasında paylaşılabiliyor olmalı.

Aşağıdaki program aynı kaynaktan — aynı `HemenHazir` tanımından — iki görev kuruyor. Biri
`kostur`a veriliyor, öbürü yalnız bir değişkene bağlanıp bir daha hiç dokunulmuyor.

```rust
// tembel.rs — ayni kaynaktan iki gorev: biri yurutucuye verilir, oburu hic dokunulmaz.
mod ilerle;
use ilerle::{kostur, HemenHazir};
use std::sync::mpsc::channel;

fn main() {
    let (gonder, al) = channel::<String>();

    // ayni kaynaktan (HemenHazir tanimindan) iki ayri gorev kuruluyor
    let yoklanan = HemenHazir {
        ad: "gorev-yoklanan",
        kanal: gonder.clone(),
    };
    let _hic_yoklanmayan = HemenHazir {
        ad: "gorev-hic-yoklanmayan",
        kanal: gonder.clone(),
    };

    // yalniz biri yurutucuye veriliyor
    let (deger, yoklama) = kostur(yoklanan);

    drop(gonder);
    let kayitlar: Vec<String> = al.try_iter().collect();

    println!("donen deger: {}", deger);
    println!("yoklama sayisi: {}", yoklama);
    println!("kayit sayisi: {}", kayitlar.len());
    for k in &kayitlar {
        println!("  {}", k);
    }
}
```

```
donen deger: gorev-yoklanan
yoklama sayisi: 1
kayit sayisi: 1
  gorev-yoklanan
```

**AS1.** Defterde tek bir kayıt var. `_hic_yoklanmayan` değişkeni kaynakta yazılı, tipi
`HemenHazir`, alanları dolu — ama karşılığında hiçbir satır basılmadı, çünkü `poll` hiç
çağrılmadı. Bu iki görev arasındaki tek fark yürütücüye verilip verilmediği; kaynak kodları,
tipleri ve alan değerleri birebir aynı yapıdan geliyor. Kayıt sayısı beş ayrı koşumda birebir
aynı kaldı: bu bir yarış değil, bir davranış.

Konunun paylaştığı ortak ölçüm çekirdeği on üç birimi aynı dört sınıfa ayırıyor: beşi kendi
başına, üçü yoklanınca, üçü başkası bitince ilerliyor, ikisi hiç ilerlemiyor. Bu dersteki iki
birim — `gorev-yoklanan` ve `gorev-hic-yoklanmayan` — o on üçlünün yoklanınca ve hiç
sınıflarından birer örnek; kalan sınıflar İş Parçacıkları konusunda ve bir sonraki derste ele
alınıyor.

Bu, kursun sorduğu sorunun ilk yanıtı. `gorev-yoklanan` **yoklanınca** ilerledi:
kendiliğinden değil, `kostur`un onu çağırmasıyla. `gorev-hic-yoklanmayan` ise **hiç**
ilerlemedi — kaynakta durdu, hiçbir zaman `poll` almadı. Trait'ler, Genellikler ve Hata
Yönetimi kursu bir gövdenin **kaç kez koştuğunu** saymıştı — her seferinde, yalnız
gerektiğinde ya da hiç. Bu kurs aynı üçlüden farklı bir soru soruyor: kaç kez koştuğu değil,
koşması için **kimin** onu ilerlettiği. `gorev-yoklanan`ı ilerleten özne `kostur`; `HemenHazir`
tipinin kendisi bu konuda hiçbir karar vermiyor, yalnız çağrıldığında ne yapacağını söylüyor.

## Bir Görev de bir Değer Üretir, Sıradan bir Çağrı Değildir

Sıradan bir fonksiyon çağrısı (`f(x)`) çağrıldığı anda çalışır; dönüş değeri geri gelene kadar
çağıran taraf bekler. `HemenHazir`in `poll` yöntemi de benzer görünüyor — çağrıldığı anda
sonucunu veriyor — ama bu, `Future` trait'inin genel kuralı değil, `HemenHazir`e özgü bir
durum. Genel kural şu: bir gelecek, `poll` çağrıldığında ya biter (`Ready`) ya da **henüz
bitmediğini söyler** (`Pending`) ve kendini bir sonraki `poll` çağrısına bırakır. `HemenHazir`
her zaman ilk çağrıda bitiyor çünkü beklediği hiçbir şey yok; bir sonraki derste kurulacak
gelecek türü ise en az bir kez `Pending` dönüyor. Bu iki uç, aynı trait'in iki farklı
gerçekleştirimi — sözleşme aynı, davranış farklı.

`poll`un imzası da bu farkı taşıyor:
`fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output>`. `Context`,
yürütücünün geleceğe verdiği tek kanal — içinde bir `Waker` taşıyor ve gelecek, kendini bir
sonraki `poll` için hazır saydığında bu `Waker`i çağırıp yürütücüye haber verebiliyor.
`HemenHazir` bunu hiç kullanmıyor çünkü hiçbir zaman `Pending` dönmüyor; sonraki ders bu
kanalı doğrudan kullanan bir gelecek kuruyor.

`Waker`in kendisi de tembel bir sözleşme taşıyor: uyandırma çağrısı yapıldığında hiçbir kod
anında çalışmıyor, yalnız yürütücüye "bu görevi tekrar yokla" diye bir işaret bırakılıyor.
`kostur`daki `Uyandirici` tipi bu işareti bir mantıksal bayrak ve bir koşul değişkeniyle
tutuyor: uyandırma çağrısı geldiğinde bayrağı `true` yapıp bekleyen döngüyü uyandırıyor. Bir
gelecek `Pending` döndürüp bu çağrıyı hiç yapmazsa, yürütücü sonsuza kadar bekler — bu,
geleceğin kendi sorumluluğu, yürütücünün değil. `HemenHazir` bu riski taşımıyor çünkü hiçbir
zaman `Pending` dönmüyor; bir sonraki derste kurulacak gelecek türü, her `Pending`
dönüşünde uyandırma çağrısını yaparak bu sözleşmeyi doğru yerine getiriyor.

`kostur`, geleceği `Box::pin` ile öbeğe yerleştiriyor. Bunun nedeni `HemenHazir`in kendisinde
yok — bu basit tip yer değiştirdiğinde hiçbir sorun çıkarmaz. Neden, bir sonraki derste
kurulacak `async fn` gövdelerinde ortaya çıkıyor: derleyici, bir `async fn`i kendi içinde
başka bir geleceği bekleyen bir durum makinesine çeviriyor ve bu makine kendi alanlarına
işaret eden referanslar taşıyabiliyor. Böyle bir değer bellekte yer değiştirirse taşıdığı
referanslar geçersiz kalır; `Pin`, bir değerin adresinin `poll` çağrıları arasında sabit
kalacağını derleyiciye söyleyen bir garantidir. `HemenHazir` bu garantiye ihtiyaç duymuyor
ama `kostur` her `Future` için aynı yolu izliyor, çünkü hangi geleceğin kendine referans
taşıyıp taşımadığını genel bir işlev bilemez. Bir sonraki derste tanıtılacak `async` yazımı da
tembellik kuralına uyuyor: eşzamansız bir fonksiyonu çağırmak onun gövdesini çalıştırmaz,
yalnız bir gelecek değeri üretir — gövdenin gerçekten çalışması, tıpkı burada `HemenHazir`de
olduğu gibi, o değerin yoklanmasını bekler.

Dikkat edilmesi gereken bir ayrıntı daha var: `kostur`un kendisi eşzamansız değil, sıradan
bir fonksiyon çağrısı. `main` içindeki `kostur(yoklanan)` satırı çalıştığında, çağıran iş
parçacığı gelecek bitene kadar bu çağrıda kalıyor — tıpkı İş Parçacıkları konusunda
birleştirmeyi bekleyen ana iş parçacığı gibi. Eşzamansızlık burada iş parçacığı sayısını
azaltmıyor; aynı iş parçacığı üzerinde birden fazla geleceği sırayla ya da iç içe ilerletmenin
bir yolunu açıyor. Bu ayrım, ilerleyen derslerde birden fazla görevin aynı yürütücü üzerinde
nasıl bir arada durabildiğini anlamanın temelini kuruyor.

## `poll` Doğrudan da Çağrılabilir

`kostur`, `poll`u bir döngü içinde çağırıyor, ama bu çağrı biçimi zorunlu değil — `poll`
sıradan bir yöntemdir ve elinde geçerli bir `Context` olan her kod onu çağırabilir.
`yoklanan.poll(&mut baglam)` `kostur`un yerine doğrudan yazılsaydı, dönüş değeri yine
`Poll::Ready("gorev-yoklanan")` olurdu — çünkü `HemenHazir` ilk çağrıda bitiyor, döngünün
kaç kez çalıştığı onun için önemsiz. Yürütücünün asıl işi bu örnekte görünmüyor: tek bir
çağrı yeten bir gelecekte yürütücü yalnızca bir aracı. Fark, bir sonraki derste kurulacak,
birden fazla `Pending` dönen gelecek türünde ortaya çıkacak — orada `poll`u ne zaman tekrar
çağıracağını bilmek, elle yazılan koddan yürütücünün sorumluluğuna geçiyor. Bu kursun sorduğu
soru tam olarak burada devreye giriyor: bir görevi ilerleten şey kendi mantığı değil, onu
çağıran kod.

## Sınırlayıcı Ölçüm

Yoklanmayan bir görev bir **hata değildir**. `_hic_yoklanmayan` derleniyor, bellekte bir
değişken olarak duruyor, kapsamı bitince bırakılıyor — ve bu sırada hiçbir hata, hiçbir uyarı
üretmiyor. Derleyici, bir `Future`in gerçekten yoklanıp yoklanmadığını izlemiyor; bunu izlemek
programcının ya da yürütücünün işi. Bu, kursun ortama bağlı veri yasağından farklı bir tür
sessizlik: burada eksik olan bir kayıt değil, hiç talep edilmemiş bir ilerlemedir. Kodun kendi
davranışı, "hiç" sınıfının neden ayrı bir hata biçimi olmadığını gösteriyor — kaynakta yazılı
bir şey, çalıştırılmadığı sürece hiçbir iz bırakmadan var olabiliyor.

Bu dersteki "hiç" örneği, konunun paylaştığı ortak ölçüm çekirdeğindeki iki "hiç" biriminden
biriyle aynı ailede: biri hiç başlatılmayan bir kapanış, öbürü hiç yoklanmayan bir görev —
ikisi de kaynakta yazılı, ikisi de derlendi, ikisi de hiçbir iz bırakmadı. İş Parçacıkları
konusunda bir birim başlatılmadan kaldığında da aynı sessizlik gözlemleniyordu; farkı, orada
sorumlu `thread::spawn`ın hiç çağrılmaması, burada `poll`un hiç çağrılmamasıydı. İkisi de aynı
kurala bağlanıyor: kaynakta yazılı olmak, ilerlemiş olmak anlamına gelmiyor.

## Özet

- Bir gelecek, `Future` trait'ini gerçekleştiren bir değerdir; tek zorunlu yöntemi `poll`,
  dönüşü `Ready` (bitti) ya da `Pending` (henüz bitmedi).
- Bir geleceğin kurulması hiçbir şeyi çalıştırmaz — yalnız `poll` çağrısı ilerletir. Bu, bir
  görevin **yoklanınca** sınıfına girmesinin temelidir.
- Aynı kaynaktan kurulan iki görevden yürütücüye verilmeyeni **hiç** ilerlemedi: kaynakta
  yazılıydı, derlendi, ama hiçbir kayıt üretmedi.
- Bir görevi ilerleten özne yürütücüdür, görevin kendisi değil — bu, bir gövdenin kaç kez
  koştuğunu sayan Trait'ler, Genellikler ve Hata Yönetimi kursundan farklı bir eksendir.
- `Context` ve `Waker`, bir geleceğin yürütücüye "hazır olduğumda haber ver" demesini sağlayan
  kanaldır; bu ders onu tanıttı, kullanımı bir sonraki derste.
- Bir iş parçacığı işletim sisteminin ayırdığı bir yürütme birimidir, bir gelecek ise salt bir
  veri değeridir — kendi başına hiçbir yürütme bağlamı taşımaz, yalnız onu yoklayan yürütücü
  çağrıldığı sürece ilerler.

## Sonraki Adım

Bu ders bir görevin kurulmasıyla ilerlemesi arasındaki farkı `HemenHazir` üzerinden gösterdi
— hiç durmayan, ilk çağrıda biten bir gelecek. Bu, mümkün en yalın gelecek türüydü: tek bir
`poll` çağrısı yetiyor, `Pending` hiç dönmüyor. Sıradaki ders aynı sözleşmeyi bir kez duran
bir gelecekle genişletiyor: duraklama noktası kaynakta nasıl görünür oluyor, `async`/`await`
yazımı bu noktaları nasıl kuruyor ve bir görevi bekleyen başka bir görev hangi sınıfa
giriyor.
