deferred-future
模仿jQuery.Deferred(),允許
-
【地點】從
Future
實現(xiàn)類實例外部 -
【時間】異步地
改變當前Future
對象的Polling
狀態(tài)從Poll::Pending
至Poll::Ready
。這個痛點是futures crate都沒有照顧到的。
功能
deferred-future crate
分別針對
-
單線程/
WASM
-
多線程
提供了兩套代碼實現(xiàn)和兩個自定義cargo feature
:
cargo feature |
FusedFuture 實現(xiàn)類 |
運行上下文 |
---|---|---|
local |
LocalDeferredFuture |
單線程/WASM |
thread |
ThreadDeferredFuture |
多線程 |
默認情況下,local
與thread
都處于開啟狀態(tài)。為了追求極致的編譯時間(短)與輸出二進制文件體積(小),屏蔽掉未被使用的模塊非常有幫助。比如,在WASM
工程內(nèi),啟用【條件編譯】和(編譯時)“裁剪”依賴包是最明智的:
# 因為 WASM 不支持【操作系統(tǒng)線程】,所以僅只導入單線程代碼實現(xiàn) deferred-future = {version = "0.1.0", features = ["local"]}
另外,因為deferred-future crate
選擇實現(xiàn)trait futures::FusedFuture,而不僅只是來自【標準庫】的std::Future,所以其對更多“邊界情況”提供了良好的容錯支持。比如,
-
重復地
Polling
一個已經(jīng)Poll::Ready(T)
的Future
實例不會導致U.B.
。
安裝
不開啟【條件編譯】
cargo add deferred-future
面向WASM
,推薦僅開啟local
cargo add deferred-future --features=local
用法
使用套路概括起來包括:
-
構(gòu)造一個
***DeferredFuture
實例-
在多線程上下文中,泛型類型參數(shù)
T
必須是Send + Sync
的。 -
在單線程上下文中,前綴
***
是Local
-
在多線程上下文中,前端
***
是Thread
-
泛型類型參數(shù)
T
對應于Future::Output
關(guān)聯(lián)類型 —— 代表了Future
就緒后輸出值的數(shù)據(jù)類型
-
-
從
***DeferredFuture
實例抽取出defer
屬性值-
被用來
Wake up
處于Pending
狀態(tài)***DeferredFuture
實例的complete(T)
成員方法就隸屬于此defer
對象。 -
在單線程上下文中,
defer
是Rc
的引用計數(shù)·智能指針> -
在多線程上下文中,
defer
是Arc
的原子加鎖引用計數(shù)·智能指針>
-
-
將
defer
對象克隆后甩到(另)一個異步任務Task
塊中去。-
在異步塊內(nèi),調(diào)用
defer
的complete(T)
成員方法。 -
在單線程上下文中,
defer
對象需被可修改借入defer.borrow_mut()
。 -
在多線程上下文中,需要先成功地獲取線程同步鎖
defer.lock().unwrap()
。
-
-
在當前執(zhí)行上下文,阻塞等待
***DeferredFuture
實例就緒和返回結(jié)果。-
就單線程而言,當前執(zhí)行上下文即是“主線程”,和同步阻塞主線程。
-
就多線程而言,當前執(zhí)行上下文就是“父異步塊”,和異步阻塞上一級異步塊。
-
下面仔細看代碼例程。請?zhí)貏e留意注釋說明。
單線程
use ::LocalDeferredFuture; use ::{future, executor::LocalPool, task::LocalSpawnExt}; use ::{prelude::*, time::Duration}; use ::Instant; // (1) 構(gòu)造·形似 jQuery.Deferred() 的 trait FusedFuture 實現(xiàn)例類實例。 // - 注意:泛型類型參數(shù) —— `Future::Output`輸出值類型是字符串。 let deferred_future = LocalDeferredFuture::default(); // (2) 取出它的 defer 實例。 let defer = deferred_future.defer(); // (3) 發(fā)起一個異步任務。在 2 秒鐘后,填入`Future::Output`輸出值。 let mut executor = LocalPool::new(); executor.spawner().spawn_local(async move { future::from_secs(2_u64)).await; // (3.1) 在異步塊內(nèi),調(diào)用`defer`的`complete(T)`成員方法。 defer.borrow_mut().complete("2秒鐘后才被延遲填入的消息".to_string()); }).unwrap(); // (4) 同步阻塞主線程等待 #3 的異步任務執(zhí)行結(jié)果,和抽取出`Future::Output`輸出值。 let start = Instant::now(); let message = executor.run_until(deferred_future); // (4.1) 會造成主線程的同步阻塞 let end = Instant::now(); let elapse = end.duration_since(start).as_secs(); println!("為了收到消息<{}>,主協(xié)程先后等待了 {} 秒", message, elapse);
從命令行,執(zhí)行命令cargo.exe run --example local-usage
可直接運行此例程。
多線程
use ::ThreadDeferredFuture; use ::{future, executor::{block_on, ThreadPool}, task::SpawnExt}; use ::{prelude::*, time::Duration}; use ::{error::Error, sync::PoisonError, time::Instant}; block_on(async move { // (1) 構(gòu)造·形似 jQuery.Deferred() 的 trait FusedFuture 實現(xiàn)類實例。 // - 注意:泛型類型參數(shù) —— `Future::Output`輸出值類型是字符串。 // - String 是 Send + Sync 的數(shù)據(jù)類型,和支持跨線程傳遞的。 let deferred_future = ThreadDeferredFuture::default(); // (2) 取出它的 defer 實例。 let defer = deferred_future.defer(); // (3) 發(fā)起一個異步任務。在 1 秒鐘后,填入`Future::Output`輸出值。 ThreadPool::new()?.spawn(async move { future::from_secs(1_u64)).await; // (3.1) 在異步塊內(nèi),調(diào)用`defer`的`complete(T)`成員方法。 let mut defer = defer.lock().unwrap_or_else(PoisonError::into_inner); defer.complete("1秒鐘后才被延遲填入的消息".to_string()); })?; // (4) 異步阻塞當前 Task 等待 #3 的異步任務執(zhí)行結(jié)果,和抽取出`Future::Output`輸出值。 let start = Instant::now(); let message = deferred_future.await; // (4.1) 會造成上一級異步塊的異步阻塞 let end = Instant::now(); let elapse = end.duration_since(start).as_secs(); println!("為了收到消息<{}>,主協(xié)程先后等待了 {} 秒", message, elapse); Ok(()) })?;
從命令行,執(zhí)行命令cargo.exe run --example thread-usage
可直接運行此例程。
WASM
use ::LocalDeferredFuture; use ::{EventStream, Options}; // (1) 構(gòu)造·形似 jQuery.Deferred() 的 trait FusedFuture 實例類實例。 // - 注意:泛型類型參數(shù) —— `Future::Output`輸出值類型是 u32。 let deferred_future = LocalDeferredFuture::default(); // (2) 取出它的 defer 實例。 let defer = deferred_future.defer(); // (3) 給按鈕 DOM 元素添加一個鼠標單擊事件。僅當按鈕被單擊時,才填入`Future::Output`輸出值。 let _ = EventStream::on(&button, "click", Options::enable_prevent_default(true), move |event| { // (3.1) 在 DOM 事件處理函數(shù)內(nèi),調(diào)用`defer`的`complete(T)`成員方法。 defer.borrow_mut().complete(12); future::ready(Ok(())) }); wasm_bindgen_futures::spawn_local(async move { // (4) 異步阻塞當前 Task 等待 #3 的按鈕點擊事件的發(fā)生,和抽取出`Future::Output`輸出值。 let result = deferred_future.await; console::info!("DeferredFuture異步結(jié)果", result); });
-
多線程
+關(guān)注
關(guān)注
0文章
278瀏覽量
19981 -
代碼
+關(guān)注
關(guān)注
30文章
4790瀏覽量
68654
原文標題:deferred-future
文章出處:【微信號:Rust語言中文社區(qū),微信公眾號:Rust語言中文社區(qū)】歡迎添加關(guān)注!文章轉(zhuǎn)載請注明出處。
發(fā)布評論請先 登錄
相關(guān)推薦
評論