Rust async 編程

来源:https://www.cnblogs.com/QiaoPengjun/archive/2023/05/26/17434443.html
-Advertisement-
Play Games

# Rust async 編程 Asynchronous Programming in Rust: 中文書名《Rust 非同步編程指南》: Rust語言聖經(Rust Course): ## 一、[Getting Started](https://rust-lang.github.io/async-b ...


Rust async 編程

Asynchronous Programming in Rust:https://rust-lang.github.io/async-book/

中文書名《Rust 非同步編程指南》:https://github.com/rustlang-cn/async-book

Rust語言聖經(Rust Course):https://course.rs/advance/async/getting-started.html

一、Getting Started

1.1 為什麼使用 async

為什麼使用 async

  • Async 編程,是一種併發(concurrent)編程模型
    • 允許你在少數系統線程上運行大量的併發任務
    • 通過 async/await 語法,看起來和同步編程差不多

其它的併發模型

  • OS 線程
    • 無需改變任何編程模型,線程間同步困難,性能開銷大
    • 線程池可以降低一些成本,但難以支撐大量 IO 綁定的工作
  • Event-driven 編程
    • 與回調函數一起用,可能高效
    • 非線性的控制流,數據流和錯誤傳播難以追蹤
  • 協程(Coroutines)
    • 類似線程,無需改變編程模型
    • 類似 async ,支持大量任務
    • 抽象掉了底層細節(這對系統編程、自定義運行時的實現很重要)
  • Actor 模型
    • 將所有併發計算劃分為 actor , 消息通信易出錯
    • 可以有效的實現 actor 模型,但許多實際問題沒解決(例如流程式控制制、重試邏輯)

Rust 中的 async

  • Future 是惰性的
    • 只有poll時才能取得進展, 被丟棄的 future 就無法取得進展了
  • Async是零成本的
    • 使用async ,可以無需堆記憶體分配(heap allocation)和動態調度(dynamic dispatch),對性能大好,且允許在受限環境使用 async
  • 不提供內置運行時
    • 運行時由Rust 社區提供,例如 tokio
  • 單線程、多線程均支持
    • 這兩者擁有各自的優缺點

Rust 中的 async 和線程(thread)

  • OS 線程:
    • 適用於少量任務,有記憶體和CPU開銷,且線程生成和線程間切換非常昂貴
    • 線程池可以降低一些成本
    • 允許重用同步代碼,代碼無需大改,無需特定編程模型
    • 有些系統支持修改線程優先順序
  • Async:
    • 顯著降低記憶體和CPU開銷
    • 同等條件下,支持比線程多幾個數量級的任務(少數線程支撐大量任務)
    • 可執行文件大(需要生成狀態機,每個可執行文件捆綁一個非同步運行時)

Async 並不是比線程好,只是不同而已!

總結:

  • 有大量 IO 任務需要併發運行時,選 async 模型
  • 有部分 IO 任務需要併發運行時,選多線程,如果想要降低線程創建和銷毀的開銷,可以使用線程池
  • 有大量 CPU 密集任務需要並行運行時,例如並行計算,選多線程模型,且讓線程數等於或者稍大於 CPU 核心數
  • 無所謂時,統一選多線程

例子

如果想併發的下載文件,你可以使用多線程如下實現:

fn get_two_sites() {
    // Spawn two threads to do work. 創建兩個新線程執行任務
    let thread_one = thread::spawn(|| download("https://www.foo.com"));
    let thread_two = thread::spawn(|| download("https://www.bar.com"));

    // Wait for both threads to complete. 等待兩個線程的完成
    thread_one.join().expect("thread one panicked");
    thread_two.join().expect("thread two panicked");
}

使用async的方式:

async fn get_two_sites_async() {
    // Create two different "futures" which, when run to completion, 創建兩個不同的`future`,你可以把`future`理解為未來某個時刻會被執行的計劃任務
    // will asynchronously download the webpages. 當兩個`future`被同時執行後,它們將併發的去下載目標頁面
    let future_one = download_async("https://www.foo.com");
    let future_two = download_async("https://www.bar.com");

    // Run both futures to completion at the same time. 同時運行兩個`future`,直至完成
    join!(future_one, future_two);
}

自定義併發模型

  • 除了線程和async,還可以用其它的併發模型(例如 event-driven)

1.2 Rust Async 的目前狀態

Async Rust 目前的狀態

  • 部分穩定,部分仍在變化。
  • 特點:
    • 針對典型併發任務,性能出色
    • 與高級語言特性頻繁交互(生命周期、pinning)
    • 同步和非同步代碼間、不同運行時的非同步代碼間存在相容性約束
    • 由於不斷進化,維護負擔更重

語言和庫的支持

  • 雖然Rust本身就支持Async編程,但很多應用依賴與社區的庫:
    • 標準庫提供了最基本的特性、類型和功能,例如 Future trait
    • async/await 語法直接被Rust編譯器支持
    • futures crate 提供了許多實用類型、巨集和函數。它們可以用於任何非同步應用程式。
    • 非同步代碼、IO 和任務生成的執行由 "async runtimes" 提供,例如 Tokio 和 async-std。大多數async 應用程式和一些 async crate 都依賴於特定的運行時。

註意

  • Rust 不允許你在 trait 里聲明 async 函數

編譯和調試

  • 編譯錯誤:
    • 由於 async 通常依賴於更複雜的語言功能,例如生命周期和Pinning,因此可能會更頻繁地遇到這些類型的錯誤。
  • 運行時錯誤:
    • 每當運行時遇到非同步函數,編譯器會在後臺生成一個狀態機,Stack traces 里有其明細,以及運行時調用的函數。因此解釋起來更複雜。
  • 新的失效模式:
    • 可能出現一些新的故障,它們可以通過編譯,甚至單元測試。

相容性考慮

  • async和同步代碼不能總是自由組合

    • 例如,不能直接從同步函數來調用 async 非同步函數
  • Async 代碼間也不總是能自由組合

    • 一些crate依賴於特定的 async 運行時
  • 因此,儘早研究確定使用哪個 async 運行時

性能特征

  • async 的性能依賴於運行時的表現(通常較出色)

1.3 async/await 入門

async

  • async 把一段代碼轉化為一個實現了Future trait 的狀態機
  • 雖然在同步方法中調用阻塞函數會阻塞整個線程,但阻塞的Future將放棄對線程的控制,從而允許其它Future來運行。
~/rust via 

您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • # 1.初識變數 編程本質就是通過一定的規則,去操縱數據,變數作為數據的載體,在程式中經常會被用到。與變數相聯繫的還有一個名詞叫數據類型,我們可以舉一個生活中的例子,來理解**數據類型-變數-數據**三者之間的關係 ![image](https://img2023.cnblogs.com/blog/ ...
  • # 使用 Rust 構建微型游戲 -- 用於理解游戲開發 ## 一、 創建游戲 ### Agenda + 建立項目 + 實現 Game loop + 不同的游戲模式 + 添加玩家 + 添加障礙和計分 + 彙總 ### 理解 Game loop 為了讓游戲流暢、順滑的運行,需要使用 Game loop ...
  • 作者:知了一笑\ 來源:juejin.cn/post/7210194936276680759 ## 一、背景 前段時間,在做項目重構的時候,遇到很多地方需要做很多的條件判斷。當然可以用很多的if-else判斷去解決,但是當時也不清楚怎麼回事,就想玩點別的。於是乎,就去調研了規則引擎。 當然,市面上有 ...
  • ### 一、哪些因素會成為系統的瓶頸? 1、CPU,如果存在大量的計算,他們會長時間不間斷的占用CPU資源,導致其他資源無法爭奪到CPU而響應緩慢,從而帶來系統性能問題,例如頻繁的FullGC,以及多線程造成的上下文頻繁的切換,都會導致CPU繁忙,一般情況下CPU使用率 作者:京東健康 牛金亮 > ...
  • 列表分類是指在Word文檔中使用不同格式排序的列表,來幫助我們一目瞭然地表達出一段文字的主要內容。比如,當我們描述了某個主題的若幹點,就可以用列表把它們一一表達出來,而不是寫成完整的段落形式。同時,列表也可以幫助我們做出精確的計算和比較,簡潔有效地表示出不同部分之間的關係。在Word文檔中創建列表可 ...
  • Java SDK 併發包里提供了豐富的原子類,我們可以將其分為五個類別,這五個類別提供的方法基本上是相似的,並且每個類別都有若幹原子類。 ...
  • ## 教程簡介 Angular Material是Angular JS開發人員的UI組件庫。 Angular Material的可重用UI組件有助於構建有吸引力,一致且功能強大的Web頁面和Web應用程式,同時遵循現代Web設計原則,如瀏覽器可移植性,設備獨立性和優雅降級。 [Angular Mat ...
  • AIGC Hackathon 2023 北京站 我參加了選手採訪提綱,這裡我感覺有些點可以分享給大家。之前復盤的鏈接: 下麵是採訪我的回答內容: ## 1. 請向大家簡單介紹一下自己吧? - 子木,社區名稱為程式員泥瓦匠,年齡三十歲,畢業於溫州醫科大學。 - 有8年SaaS經驗,曾在有贊和售後寶等S ...
一周排行
    -Advertisement-
    Play Games
  • 1、預覽地址:http://139.155.137.144:9012 2、qq群:801913255 一、前言 隨著網路的發展,企業對於信息系統數據的保密工作愈發重視,不同身份、角色對於數據的訪問許可權都應該大相徑庭。 列如 1、不同登錄人員對一個數據列表的可見度是不一樣的,如數據列、數據行、數據按鈕 ...
  • 前言 上一篇文章寫瞭如何使用RabbitMQ做個簡單的發送郵件項目,然後評論也是比較多,也是準備去學習一下如何確保RabbitMQ的消息可靠性,但是由於時間原因,先來說說設計模式中的簡單工廠模式吧! 在瞭解簡單工廠模式之前,我們要知道C#是一款面向對象的高級程式語言。它有3大特性,封裝、繼承、多態。 ...
  • Nodify學習 一:介紹與使用 - 可樂_加冰 - 博客園 (cnblogs.com) Nodify學習 二:添加節點 - 可樂_加冰 - 博客園 (cnblogs.com) 介紹 Nodify是一個WPF基於節點的編輯器控制項,其中包含一系列節點、連接和連接器組件,旨在簡化構建基於節點的工具的過程 ...
  • 創建一個webapi項目做測試使用。 創建新控制器,搭建一個基礎框架,包括獲取當天日期、wiki的請求地址等 創建一個Http請求幫助類以及方法,用於獲取指定URL的信息 使用http請求訪問指定url,先運行一下,看看返回的內容。內容如圖右邊所示,實際上是一個Json數據。我們主要解析 大事記 部 ...
  • 最近在不少自媒體上看到有關.NET與C#的資訊與評價,感覺大家對.NET與C#還是不太瞭解,尤其是對2016年6月發佈的跨平臺.NET Core 1.0,更是知之甚少。在考慮一番之後,還是決定寫點東西總結一下,也回顧一下.NET的發展歷史。 首先,你沒看錯,.NET是跨平臺的,可以在Windows、 ...
  • Nodify學習 一:介紹與使用 - 可樂_加冰 - 博客園 (cnblogs.com) Nodify學習 二:添加節點 - 可樂_加冰 - 博客園 (cnblogs.com) 添加節點(nodes) 通過上一篇我們已經創建好了編輯器實例現在我們為編輯器添加一個節點 添加model和viewmode ...
  • 前言 資料庫併發,數據審計和軟刪除一直是數據持久化方面的經典問題。早些時候,這些工作需要手寫複雜的SQL或者通過存儲過程和觸發器實現。手寫複雜SQL對軟體可維護性構成了相當大的挑戰,隨著SQL字數的變多,用到的嵌套和複雜語法增加,可讀性和可維護性的難度是幾何級暴漲。因此如何在實現功能的同時控制這些S ...
  • 類型檢查和轉換:當你需要檢查對象是否為特定類型,並且希望在同一時間內將其轉換為那個類型時,模式匹配提供了一種更簡潔的方式來完成這一任務,避免了使用傳統的as和is操作符後還需要進行額外的null檢查。 複雜條件邏輯:在處理複雜的條件邏輯時,特別是涉及到多個條件和類型的情況下,使用模式匹配可以使代碼更 ...
  • 在日常開發中,我們經常需要和文件打交道,特別是桌面開發,有時候就會需要載入大批量的文件,而且可能還會存在部分文件缺失的情況,那麼如何才能快速的判斷文件是否存在呢?如果處理不當的,且文件數量比較多的時候,可能會造成卡頓等情況,進而影響程式的使用體驗。今天就以一個簡單的小例子,簡述兩種不同的判斷文件是否... ...
  • 前言 資料庫併發,數據審計和軟刪除一直是數據持久化方面的經典問題。早些時候,這些工作需要手寫複雜的SQL或者通過存儲過程和觸發器實現。手寫複雜SQL對軟體可維護性構成了相當大的挑戰,隨著SQL字數的變多,用到的嵌套和複雜語法增加,可讀性和可維護性的難度是幾何級暴漲。因此如何在實現功能的同時控制這些S ...