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函式無法滿足需求。
本作品採用《CC 協議》,轉載必須註明作者和本文連結