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