日韩成人免费在线_国产成人一二_精品国产免费人成电影在线观..._日本一区二区三区久久久久久久久不

當前位置:首頁 > 科技  > 軟件

在 Rust 編程中使用多線程

來源: 責編: 時間:2024-01-08 09:15:59 201觀看
導讀1. Rust線程實現理念在大部分現代操作系統中,已執行程序的代碼在一個 進程(process)中運行,操作系統則會負責管理多個進程。在程序內部,也可以擁有多個同時運行的獨立部分。這些運行這些獨立部分的功能被稱為 線程(threads)

1. Rust線程實現理念

在大部分現代操作系統中,已執行程序的代碼在一個 進程(process)中運行,操作系統則會負責管理多個進程。在程序內部,也可以擁有多個同時運行的獨立部分。這些運行這些獨立部分的功能被稱為 線程(threads)。例如,web 服務器可以有多個線程以便可以同時響應多個請求。zGn28資訊網——每日最新資訊28at.com

zGn28資訊網——每日最新資訊28at.com

將程序中的計算拆分進多個線程可以改善性能,因為程序可以同時進行多個任務,不過這也會增加復雜性。因為線程是同時運行的,所以無法預先保證不同線程中的代碼的執行順序。這會導致諸如此類的問題:zGn28資訊網——每日最新資訊28at.com

  • 競態條件(Race conditions),多個線程以不一致的順序訪問數據或資源。
  • 死鎖(Deadlocks),兩個線程相互等待對方,這會阻止兩者繼續運行。
  • 只會發生在特定情況且難以穩定重現和修復的 bug。

Rust 嘗試減輕使用線程的負面影響。不過在多線程上下文中編程仍需格外小心,同時其所要求的代碼結構也不同于運行于單線程的程序。zGn28資訊網——每日最新資訊28at.com

編程語言有一些不同的方法來實現線程,而且很多操作系統提供了創建新線程的 API。Rust 標準庫使用 1:1 線程實現,這代表程序的每一個語言級線程使用一個系統線程。zGn28資訊網——每日最新資訊28at.com

2.使用spawn創建新線程

為了創建一個新線程,需要調用 thread::spawn 函數并傳遞一個閉包, 并在其中包含希望在新線程運行的代碼??聪旅娴睦?zGn28資訊網——每日最新資訊28at.com

use std::thread;use std::time::Duration;fn main() {    thread::spawn(|| {        for i in 1..10 {            println!("hi number {} from the spawned thread!", i);            thread::sleep(Duration::from_millis(1));        }    });    for i in 1..5 {        println!("hi number {} from the main thread!", i);        thread::sleep(Duration::from_millis(1));    }}

注意當 Rust 程序的主線程結束時,新線程也會結束,而不管其是否執行完畢。這個程序的輸出可能每次都略有不同,不過它大體上看起來像這樣:zGn28資訊網——每日最新資訊28at.com

zGn28資訊網——每日最新資訊28at.com

thread::sleep 調用強制線程停止執行一小段時間,這會允許其他不同的線程運行。這些線程可能會輪流運行,不過并不保證如此:這依賴操作系統如何調度線程。在這里,主線程首先打印,即便新創建線程的打印語句位于程序的開頭,甚至即便我們告訴新建的線程打印直到 i 等于 9,它在主線程結束之前也只打印到了 5。zGn28資訊網——每日最新資訊28at.com

如果運行代碼只看到了主線程的輸出,或沒有出現重疊打印的現象,嘗試增大區間 (變量 i 的范圍) 來增加操作系統切換線程的機會。zGn28資訊網——每日最新資訊28at.com

3.使用join等待所有線程結束

由于主線程結束,上面演示的代碼大部分時候不光會提早結束新建線程,因為無法保證線程運行的順序,甚至不能實際保證新建線程會被執行!zGn28資訊網——每日最新資訊28at.com

可以通過將 thread::spawn 的返回值儲存在變量中來修復新建線程部分沒有執行或者完全沒有執行的問題。thread::spawn 的返回值類型是 JoinHandle。JoinHandle 是一個擁有所有權的值,當對其調用 join 方法時,它會等待其線程結束。zGn28資訊網——每日最新資訊28at.com

看下面的示例代碼:zGn28資訊網——每日最新資訊28at.com

use std::thread;use std::time::Duration;fn main() {    let handle = thread::spawn(|| {        for i in 1..10 {            println!("hi number {} from the spawned thread!", i);            thread::sleep(Duration::from_millis(1));        }    });    for i in 1..5 {        println!("hi number {} from the main thread!", i);        thread::sleep(Duration::from_millis(1));    }    handle.join().unwrap();}

通過調用 handle 的 join 會阻塞當前線程直到 handle 所代表的線程結束。阻塞(Blocking)線程意味著阻止該線程執行工作或退出。因為我們將 join 調用放在了主線程的 for 循環之后,編譯這段代碼后運行結果如下:zGn28資訊網——每日最新資訊28at.com

zGn28資訊網——每日最新資訊28at.com

這兩個線程仍然會交替執行,不過主線程會由于 handle.join() 調用會等待直到新建線程執行完畢。zGn28資訊網——每日最新資訊28at.com

不過如果將 handle.join() 移動到 main 中 for 循環之前會發生什么呢,看下面的代碼:zGn28資訊網——每日最新資訊28at.com

use std::thread;use std::time::Duration;fn main() {    let handle = thread::spawn(|| {        for i in 1..10 {            println!("hi number {} from the spawned thread!", i);            thread::sleep(Duration::from_millis(1));        }    });    handle.join().unwrap();    for i in 1..5 {        println!("hi number {} from the main thread!", i);        thread::sleep(Duration::from_millis(1));    }}

代碼編譯執行后結果如下:zGn28資訊網——每日最新資訊28at.com

zGn28資訊網——每日最新資訊28at.com

主線程會等待直到新建線程執行完畢之后才開始執行 for 循環,所以輸出將不會交替出現。zGn28資訊網——每日最新資訊28at.com

因此,將join放在代碼的不同地方, 將會影響線程是否同時執行。zGn28資訊網——每日最新資訊28at.com

4.將move閉包與線程一起使用

move 關鍵字經常用于傳遞給 thread::spawn 的閉包,因為閉包會獲取從環境中取得的值的所有權,因此會將這些值的所有權從一個線程傳送到另一個線程。zGn28資訊網——每日最新資訊28at.com

為了在新建線程中使用來自于主線程的數據,需要新建線程的閉包獲取它需要的值, 下面的代碼展示了一個嘗試在主線程中創建一個 vector 并用于新建線程的例子,不過這么寫還不能工作, 代碼如下:zGn28資訊網——每日最新資訊28at.com

use std::thread;fn main() {    let v = vec![1, 2, 3];    let handle = thread::spawn(|| {        println!("Here's a vector: {:?}", v);    });    handle.join().unwrap();}

閉包使用了 v,所以閉包會捕獲 v 并使其成為閉包環境的一部分。因為 thread::spawn 在一個新線程中運行這個閉包,所以可以在新線程中訪問 v。然而當編譯這個例子時,會得到如下錯誤:zGn28資訊網——每日最新資訊28at.com

zGn28資訊網——每日最新資訊28at.com

Rust 會 推斷 如何捕獲 v,因為 println! 只需要 v 的引用,閉包嘗試借用 v。然而這有一個問題:Rust 不知道這個新建線程會執行多久,所以無法知曉對 v 的引用是否一直有效。zGn28資訊網——每日最新資訊28at.com

看一段比較極端情況的代碼:zGn28資訊網——每日最新資訊28at.com

use std::thread;fn main() {    let v = vec![1, 2, 3];    let handle = thread::spawn(|| {        println!("Here's a vector: {:?}", v);    });    drop(v); // 壞事兒了!    handle.join().unwrap();}

如果 Rust 允許這段代碼運行,則新建線程則可能會立刻被轉移到后臺并完全沒有機會運行。新建線程內部有一個 v 的引用,不過主線程立刻就使用drop丟棄了v。接著當新建線程開始執行,v 已不再有效,所以其引用也是無效的。zGn28資訊網——每日最新資訊28at.com

為了修復上面的編譯錯誤, 我們可以根據編譯器給予我們的help嘗試修正一下,如圖:zGn28資訊網——每日最新資訊28at.com

zGn28資訊網——每日最新資訊28at.com

通過在閉包之前增加 move 關鍵字,強制閉包獲取其使用的值的所有權,而不是任由 Rust 推斷它應該借用值。zGn28資訊網——每日最新資訊28at.com

修正后的代碼如下:zGn28資訊網——每日最新資訊28at.com

use std::thread;fn main() {    let v = vec![1, 2, 3];    let handle = thread::spawn(move || {        println!("Here's a vector: {:?}", v);    });    handle.join().unwrap();}

編譯運行試一下:zGn28資訊網——每日最新資訊28at.com

zGn28資訊網——每日最新資訊28at.com

看起來沒問題,那么以這個成功的經驗, 修改那段極端情況的代碼如下:zGn28資訊網——每日最新資訊28at.com

use std::thread;fn main() {    let v = vec![1, 2, 3];    let handle = thread::spawn(move || {        println!("Here's a vector: {:?}", v);    });    drop(v); // 壞事兒了!    handle.join().unwrap();}

再次編譯一下看看結果如何:zGn28資訊網——每日最新資訊28at.com

zGn28資訊網——每日最新資訊28at.com

Rust編譯器依然沒有放行, 這個修復行不通。zGn28資訊網——每日最新資訊28at.com

如果為閉包增加 move,將會把 v 移動進閉包的環境中, 因此將不能在主線程中對其調用 drop 了, Rust 的所有權規則又一次幫助我們杜絕了隱患。因為 Rust 是保守的并只會為線程借用 v,這意味著主線程理論上可能使新建線程的引用無效。通過告訴 Rust 將 v 的所有權移動到新建線程,我們向 Rust 保證主線程不會再使用 v。如果對其作出同樣的move修改, 那么當在主線程中使用 v 時就會違反所有權規則。move 關鍵字覆蓋了 Rust 默認保守的借用,但它不允許我們違反所有權規則。zGn28資訊網——每日最新資訊28at.com

本文鏈接:http://www.www897cc.com/showinfo-26-57882-0.html在 Rust 編程中使用多線程

聲明:本網頁內容旨在傳播知識,若有侵權等問題請及時與本網聯系,我們將在第一時間刪除處理。郵件:2376512515@qq.com

上一篇: 手把手教你用Go語言開發一款簡易目錄生成器

下一篇: 檢測臉部情緒有多難?10行代碼就可以搞定!

標簽:
  • 熱門焦點
  • 影音體驗是真的強 簡單聊聊iQOO Pad

    大公司的好處就是產品線豐富,非常細分化的東西也能給你做出來,例如早先我們看到了新的vivo Pad2,之后我們又在iQOO Neo8 Pro的發布會上看到了iQOO的首款平板產品iQOO Pad。雖
  • 5月安卓手機好評榜:魅族20 Pro奪冠

    性能榜和性價比榜之后,我們來看最后的安卓手機好評榜,數據來源安兔兔評測,收集時間2023年5月1日至5月31日,僅限國內市場。第一名:魅族20 Pro好評率:97.50%不得不感慨魅族老品牌還
  • 深度探索 Elasticsearch 8.X:function_score 參數解讀與實戰案例分析

    在 Elasticsearch 中,function_score 可以讓我們在查詢的同時對搜索結果進行自定義評分。function_score 提供了一系列的參數和函數讓我們可以根據需求靈活地進行設置。近期
  • 阿里大調整

    來源:產品劉有媒體報道稱,近期淘寶天貓集團啟動了近年來最大的人力制度改革,涉及員工績效、層級體系等多個核心事項,目前已形成一個初步的“征求意見版”:1、取消P序列
  • 到手價3099元起!iQOO Neo8 Pro今日首銷:安卓性能最強旗艦

    5月23日,iQOO如期舉行了新品發布會,全新的iQOO Neo8系列也正式與大家見面,包含iQOO Neo8和iQOO Neo8 Pro兩個版本,其中標準版搭載高通驍龍8+,而Pro版更
  • iQOO Neo8系列今日官宣:首發天璣9200+ 全球安卓最強芯!

    在昨日舉行的的聯發科新一代旗艦芯片天璣9200+的發布會上,iQOO官方也正式宣布,全新的iQOO Neo8系列新品將全球首發搭載這款當前性能最強大的移動平臺
  • 微軟發布Windows 11新版 引入全新任務欄狀態

    近日,微軟發布了Windows 11新版,而Build 22563更新主要引入了幾周前曝光的平板模式任務欄等,系統更流暢了。更新中,Windows 11加入了專門針對平板優化的任務欄
  • 蘋果MacBook Pro 2021測試:仍不支持平滑滾動

    據10月30日9to5 Mac 消息報道,蘋果新的 14 英寸和 16 英寸 MacBook Pro 2021 上市后獲得了不錯的評價,亮點包括行業領先的性能,令人印象深刻的電池續航,精美豐
  • 世界人工智能大會國際日開幕式活動在世博展覽館開啟

    30日上午,世界人工智能大會國際日開幕式活動在世博展覽館開啟,聚集國際城市代表、重量級院士專家、國際創新企業代表,共同打造人工智能交流平臺。上海市副市
Top 主站蜘蛛池模板: 武义县| 杭锦旗| 莆田市| 固镇县| 大英县| 靖远县| 昔阳县| 东乡县| 莱阳市| 锦州市| 阿合奇县| 玉溪市| 扶绥县| 隆尧县| 揭西县| 鄂温| 宁阳县| 成都市| 顺平县| 基隆市| 神农架林区| 大兴区| 宁陵县| 临桂县| 嵩明县| 城步| 盐源县| 西安市| 镇远县| 康乐县| 元朗区| 三河市| 凌云县| 镇康县| 石首市| 高淳县| 宝鸡市| 新建县| 河北省| 江川县| 香港|