在 Rust 裡使用非同步(Asynchronous)

閱讀時間約 8 分鐘

非同步程式設計(Asynchronous programming) 或是簡單的稱之為 async,它是一種並發程式模型(concurrent programming model),其目的就是讓多個任務能同時在作業系統的執行緒上執行,並透過 async/.await 保留同步。

Sync 與 Async 簡單的分別:

  • 同步(Sync):做完一件事情後再做下一件
  • 非同步(Async):一件事情還沒完成時,可以先做其他不衝突的事情
    • 並發、並行(Concurrency):在同個程式下,各個任務可獨立執行平行(Parallelism):同時執行多個程式
    • 平行(Parallelism):同時執行多個程式

Async 與其他並發程式模型

根據不同程式語言所支持的並發程式模型,以下列出幾種常見的幾種:

  • 作業系統執行緒(OS threads):不需要改變任何程式模型,就可以簡單的達成並發,但是,各個執行緒之間要同步就很困難,而且需要更多的效能,不夠應付大量密集的 IO 工作
  • 事件驅動程式設計(Event-driven programming):最相關的關鍵詞就是 callback,高效率但語法很容易過冗,而且很難追蹤資料流與錯誤的問題
  • 協程(Coroutines):與 threads 一樣不需要改變任何程式模型,就可以簡單的達成並發。與 async 一樣可支援大量任務,不過它抽象化了許多系統程式設計與自訂運行的低階細節
  • 演員模型(Actor Model):將所有並發計算切成 actor 的單元,並透過 message 溝通,很像分散式系統。不過有很多問題待解決,例如:流量控制、邏輯問題

與上述做比較,在 Rust 等低階程式語言裡,使用非同步程式設計可以實現高性能並同時提供 threads 與 coroutines 的各式優點。

在 Rust 裡的 Async 與 threads

如果在 Rust 使用 OS threads,可以使用 std::threads 或間接訪問 threads pool。

OS threads

OS threads 適合少量任務,執行緒會使用到 CPU 與記憶體,生成 threads 和在 threads 之間切換是很耗效能的,連空閒的 threads 也會消耗效能,雖然使用 threads pool 可以減輕一些使用成本,但也不是全部。

Threads 能讓你重複使用已存在的同步程式碼,而不需要大幅的改變程式,也不需要特定的設計模型,在一些特定的 OS 中,你還可以設定 threads 的優先級來決定誰先執行。

Async

Async 明顯的減少 CPU 與記憶體的消耗,特別是對於具有大量密集的 IO 工作,例如:伺服器和資料庫。在同等的條件下,使用 async 可以處理比 OS threads 更多的任務,這是因為 async 使用了少量的 threads 來處理大量的簡單任務。

最後要註明一點,並不是 async 比 threads 好,而是要根據當下的狀況來選擇使用,如果你不需要 async 的功能,直接使用 threads 反而是更簡單的方式。

實例比較

建立兩個 threads 來同時下載兩個網頁:

fn get_two_sites() {
// 產生兩個 threads
let thread_one = thread::spawn(|| download("https://www.foo.com"));
let thread_two = thread::spawn(|| download("https://www.bar.com"));

// 等待 threads 完成工作
thread_one.join().expect("thread one panicked");
thread_two.join().expect("thread two panicked");
}

不過這種簡單的任務建立兩個 threads 是很浪費的,在大型的應用程式中每一點資源都是很重要的,所以在這裡,我們可以選擇 Rust 中的 async 方式,既不需要使用額外的執行緒,還可以達成並發的功能:

async fn get_two_sites_async() {
// 建立兩個不同的 futures,當運行程式會使用 async 的方式來下載
let future_one = download_async("https://www.foo.com");
let future_two = download_async("https://www.bar.com");

// 同時執行兩個 futures
join!(future_one, future_two);
}

這樣寫的話就不會產生額外的 threads,當然唯一的重點就是要自己完成 download_async 的非同步程式碼。

async/.await

async/.await 是 Rust 內建將非同步編寫成像同步程式碼的方式,async 會將這個指定的區塊轉成一個狀態機制(state machine),稱為 Future

Future 是 Rust 裡非同步(Async) 任務的狀態:

  • poll:不斷查詢任務是否完成
    • Pending:任務還在執行Ready(val):如果成功完成任務,則連同結果一起回傳
    • Ready(val):如果成功完成任務,則連同結果一起回傳

實際操作

這裡使用教學裡的 futures 來實現非同步程式碼,首先新增依賴項到 Cargo.toml

[dependencies]
futures = "0.3"

接著在更改 src/main.rs

// `block_on` 會阻擋目前的 thread 直到 future 完成
use futures::executor::block_on;

async fn hello_world() {
println!("hello, world!");
}

fn main() {
let future = hello_world();
block_on(future);
}

這邊來更改使用 async/.await 來寫:

use futures::executor::block_on;
use std::{thread, time::Duration};

async fn read_book() {
// 設定一個等待時間
thread::sleep(Duration::from_secs(1));
}

async fn tell_story() {
// 等待完成後才會繼續
read_book().await;
println!("Book content");
}

async fn hand_move() {
println!("Hand move");
}

async fn async_main() {
let f1 = tell_story();
let f2 = hand_move();

// `join!` 類似於 `.await` 可以一次等待多個 futures
futures::join!(f1, f2);
}

fn main() {
block_on(async_main());
}

根據以上的例子,要先讀一本書的內容才能開始說故事,在說故事的期間同時還會有一些肢體動作,如果沒有先讀那本書,後面的動作則無法成立。

結語

以上是一個簡單的 Rust 實作 Async 的方式,在依賴項的部分,你也可以使用更多人在用的 tokio 來實現非同步。

Reference

avatar-img
2會員
4內容數
簡單的了解一個關於程式相關的主題
留言0
查看全部
avatar-img
發表第一個留言支持創作者!
Soft Code 的其他內容
對於剛學習 Rust 的人來說,最一開始不是看 Youtube 的影片或是跟著 Rust 官方手冊 The Book 學習,這邊來推薦一個練習 Rust 的專案,名為 rustlings。 rustlings 包含著一些簡單的題目,來讓你更習慣閱讀或編寫 Rust 程式碼。該專案會在每道題目上給予
Bun 在 2023/9/8 釋出了 1.0 版本,這篇文章就來說一下為什麼 Bun 會被關注,還有該怎麼使用它。
對於剛學習 Rust 的人來說,最一開始不是看 Youtube 的影片或是跟著 Rust 官方手冊 The Book 學習,這邊來推薦一個練習 Rust 的專案,名為 rustlings。 rustlings 包含著一些簡單的題目,來讓你更習慣閱讀或編寫 Rust 程式碼。該專案會在每道題目上給予
Bun 在 2023/9/8 釋出了 1.0 版本,這篇文章就來說一下為什麼 Bun 會被關注,還有該怎麼使用它。
你可能也想看
Google News 追蹤
Thumbnail
這個秋,Chill 嗨嗨!穿搭美美去賞楓,裝備款款去露營⋯⋯你的秋天怎麼過?秋日 To Do List 等你分享! 秋季全站徵文,我們準備了五個創作主題,參賽還有機會獲得「火烤兩用鍋」,一起來看看如何參加吧~
Thumbnail
11/20日NVDA即將公布最新一期的財報, 今天Sell Side的分析師, 開始調高目標價, 市場的股價也開始反應, 未來一週NVDA將重新回到美股市場的焦點, 今天我們要分析NVDA Sell Side怎麼看待這次NVDA的財報預測, 以及實際上Buy Side的倉位及操作, 從
Thumbnail
Hi 大家好,我是Ethan😊 相近大家都知道保濕是皮膚保養中最基本,也是最重要的一步。無論是在畫室裡長時間對著畫布,還是在旅途中面對各種氣候變化,保持皮膚的水分平衡對我來說至關重要。保濕化妝水不僅能迅速為皮膚補水,還能提升後續保養品的吸收效率。 曾經,我的保養程序簡單到只包括清潔和隨意上乳液
Thumbnail
下午的廣場遊戲時間,小朋友們自由的在各處奔走探索。 柏炘:挖到寶了!這裡還有一隻大蝸牛耶! 昱徳:真的耶!是大蝸牛。 子郁:我們把它拿到那邊(玩土區)。 星星:媽媽說吃土很健康。(挖洞中) 昱徳:這個土是飯喔! 子恩:要把它(蝸牛)埋了嗎? 瑜希:沒有,我們要煮菜。 小朋
Thumbnail
各位大四的同學: 六月初我們一起度過了一段愉快的時光,解開了一些成就,常規之內的課程帶給我們彼此意外的收穫。
現在的學生都那麼早熟嗎?已經開始使用飛機杯了,直接把他沒收拿來自己用,沒有啦~開玩笑的,這種東西是能跟別人共用的嗎。今天來幫大家上課一下,飛機杯是什麼?除了介紹材質之外,順便幫你們介紹挑選飛機杯的要點。 飛機杯是什麼 飛機杯的材質? 如果要推薦飛機杯款式的話,我會建議你以下幾點: 可重複使用
Thumbnail
在馬來西亞想去菲律賓旅遊~如何辦理簽證呢?​​ 現在很多國家都慢慢開放入境旅遊拉~ 以台灣籍的來說,去菲律賓辦理簽證有兩種:1.上網辦理電子簽證 2.紙本簽證 但是現在只開放紙本簽證😰😰 人在異國,該怎麼辦理簽證呢? 今天芮芮就來告訴你啦~ 有你的支持才是我繼續創作的動力(拜偷📷📷​) -
寫作的世界裡,有些字詞是沒辦法存在的,只是我們不願意直說,反而運用了字詞之間本就有相近意思而可以相互解釋的彈性,巧妙去迴避掉我們原初想說的本來。
「說是信任也好,說是愛也好,    說這是天意,也差不了多少,    依偎著你,讓我找到了依靠,    多謝繁星引導。    說你很遠,就像在天涯海角;    說你很近,又如影子般纏繞;    依偎著
Thumbnail
<p>我使用文字思考。但同時我又感覺到,有些東西是我說不出來,形容不出來,寫不出來的。</p>
Thumbnail
<p>在中國討生活的外國人們,大致上分成三類人:靠長相吃飯的「白猴子」、外商跨國公司派至中國的「洋總督」、和卡在中間來追求中國夢的「勇敢的外國人」。第一類是靠長相混飯吃的外國人們,第二類是高階主管,而最後一類是那些看好中國市場,來中國創業或是打工的外國人。</p>
Thumbnail
<p>幾千年來,就這麼春去春又來,燕子始終陪伴著我們,提醒著我們。可是絕大部份人卻不知道也沒看過,究竟燕子如何帶著這些小燕子離去?又如何成雙成對地回到原來的燕巢?</p>
Thumbnail
這個秋,Chill 嗨嗨!穿搭美美去賞楓,裝備款款去露營⋯⋯你的秋天怎麼過?秋日 To Do List 等你分享! 秋季全站徵文,我們準備了五個創作主題,參賽還有機會獲得「火烤兩用鍋」,一起來看看如何參加吧~
Thumbnail
11/20日NVDA即將公布最新一期的財報, 今天Sell Side的分析師, 開始調高目標價, 市場的股價也開始反應, 未來一週NVDA將重新回到美股市場的焦點, 今天我們要分析NVDA Sell Side怎麼看待這次NVDA的財報預測, 以及實際上Buy Side的倉位及操作, 從
Thumbnail
Hi 大家好,我是Ethan😊 相近大家都知道保濕是皮膚保養中最基本,也是最重要的一步。無論是在畫室裡長時間對著畫布,還是在旅途中面對各種氣候變化,保持皮膚的水分平衡對我來說至關重要。保濕化妝水不僅能迅速為皮膚補水,還能提升後續保養品的吸收效率。 曾經,我的保養程序簡單到只包括清潔和隨意上乳液
Thumbnail
下午的廣場遊戲時間,小朋友們自由的在各處奔走探索。 柏炘:挖到寶了!這裡還有一隻大蝸牛耶! 昱徳:真的耶!是大蝸牛。 子郁:我們把它拿到那邊(玩土區)。 星星:媽媽說吃土很健康。(挖洞中) 昱徳:這個土是飯喔! 子恩:要把它(蝸牛)埋了嗎? 瑜希:沒有,我們要煮菜。 小朋
Thumbnail
各位大四的同學: 六月初我們一起度過了一段愉快的時光,解開了一些成就,常規之內的課程帶給我們彼此意外的收穫。
現在的學生都那麼早熟嗎?已經開始使用飛機杯了,直接把他沒收拿來自己用,沒有啦~開玩笑的,這種東西是能跟別人共用的嗎。今天來幫大家上課一下,飛機杯是什麼?除了介紹材質之外,順便幫你們介紹挑選飛機杯的要點。 飛機杯是什麼 飛機杯的材質? 如果要推薦飛機杯款式的話,我會建議你以下幾點: 可重複使用
Thumbnail
在馬來西亞想去菲律賓旅遊~如何辦理簽證呢?​​ 現在很多國家都慢慢開放入境旅遊拉~ 以台灣籍的來說,去菲律賓辦理簽證有兩種:1.上網辦理電子簽證 2.紙本簽證 但是現在只開放紙本簽證😰😰 人在異國,該怎麼辦理簽證呢? 今天芮芮就來告訴你啦~ 有你的支持才是我繼續創作的動力(拜偷📷📷​) -
寫作的世界裡,有些字詞是沒辦法存在的,只是我們不願意直說,反而運用了字詞之間本就有相近意思而可以相互解釋的彈性,巧妙去迴避掉我們原初想說的本來。
「說是信任也好,說是愛也好,    說這是天意,也差不了多少,    依偎著你,讓我找到了依靠,    多謝繁星引導。    說你很遠,就像在天涯海角;    說你很近,又如影子般纏繞;    依偎著
Thumbnail
<p>我使用文字思考。但同時我又感覺到,有些東西是我說不出來,形容不出來,寫不出來的。</p>
Thumbnail
<p>在中國討生活的外國人們,大致上分成三類人:靠長相吃飯的「白猴子」、外商跨國公司派至中國的「洋總督」、和卡在中間來追求中國夢的「勇敢的外國人」。第一類是靠長相混飯吃的外國人們,第二類是高階主管,而最後一類是那些看好中國市場,來中國創業或是打工的外國人。</p>
Thumbnail
<p>幾千年來,就這麼春去春又來,燕子始終陪伴著我們,提醒著我們。可是絕大部份人卻不知道也沒看過,究竟燕子如何帶著這些小燕子離去?又如何成雙成對地回到原來的燕巢?</p>