Future介紹
Future是Rust異步編程的核心,Rust異步編程基本都是圍繞Future來展開。那麼,什麼是Future呢? 首先,我們來看下簡化版的Future,如下:
trait SimpleFuture { type Output; fn poll(&mut self, wake: fn()) -> Poll<Self::Output>; } enum Poll<T> { Ready(T), Pending, }
- executor Future的執行者,Future是具有的惰性的,並不會自己的執行,所以需要有一個執行者(executor)來執行Future。
- Poll枚舉類型
表示Future的兩個狀態:Ready爲完成狀態,Pengding爲未完成狀態。
- poll函數
executor通過調用poll函數可以推進Future的狀態。調用poll時,如果完成,返回Ready狀態;如果未完成則返回pengding狀態。當wake函數被調用後,會通知executor再次調用poll函數。
- wake函數
當Future變成Ready狀態後,wake函數會被調用,executor就知道哪個Future已經準備好了,然後調用poll函數。
使用SimpleFuture
use std::thread; use std::time::Duration; enum Poll<T> { Ready(T), Pending, } trait SimpleFuture { type Output; //fn poll(&mut self, wake: fn()) -> Poll<Self::Output>; fn poll(&mut self, wake: u32) -> Poll<Self::Output>; } static mut FINISHED: bool = false; struct MySleeper { polls: u64, wake: u32, } impl MySleeper { fn new() -> Self { MySleeper { polls: 0, wake: 0, } } } impl SimpleFuture for MySleeper { type Output = (); fn poll(&mut self, wake: u32) -> Poll<()> { unsafe { if FINISHED { Poll::Ready(()) } else { self.wake = wake; self.polls += 1; println!("not ready yet --> {}", self.polls); Poll::Pending } } } } struct MyReactor { wake: u32, handle: Option<thread::JoinHandle<()>>, } impl MyReactor { fn new() -> MyReactor { MyReactor { wake: 0, handle: None, } } fn add_wake(&mut self, wake: u32) { self.wake = wake; } fn check_status(&mut self) { if self.handle.is_none() { let _wake = self.wake; let handle = thread::spawn(|| loop { thread::sleep(Duration::from_secs(5)); {//模擬執行wake函數 unsafe { FINISHED = true; } } }); self.handle = Some(handle); } } } struct MyExecutor; impl MyExecutor { fn block_on<F: SimpleFuture>(mut my_future: F, wake: u32) { loop { match my_future.poll(wake) { Poll::Ready(_) => { println!("my future execute ok!"); break; }, Poll::Pending => { unsafe { while !FINISHED {//FINISHED爲true表示爲喚醒 thread::sleep(Duration::from_secs(1)); } } } } } } } fn main() { let mut reactor = MyReactor::new(); let sleeper = MySleeper::new(); let wake = sleeper.wake; reactor.add_wake(wake); reactor.check_status(); MyExecutor::block_on(sleeper, wake); }
- SimpleFuture
簡化版的Future,實際上是一個狀態機。
- MyExecutor
用來執行SimpleFuture的相關動作。
- MyReactor
用來檢測條件是否就位,從而通知MyExecutor執行SimpleFuture。
真正的Future trait
真正的Future的定義如下:
trait Future { type Output; fn poll( // Note the change from `&mut self` to `Pin<&mut Self>`: self: Pin<&mut Self>, // and the change from `wake: fn()` to `cx: &mut Context<'_>`: cx: &mut Context<'_>, ) -> Poll<Self::Output>; }
真正的Future中,poll函數中self的類型變爲了Pin<&mut Self>,第二個參數wake: fn()變爲 &mut Context<'_>。
第一個改變是因爲,通過Pin可以創建不可移動的 Future。不可移動的對象可以在它們的字段之間存儲指針,例如:
struct MyFut { a: i32, ptr_to_a: *const i32 }
第二個改變是因爲,喚醒Future的時候,需要帶一些數據,我們之前的只是wake函數無法滿足需求。