欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Rust如何使用線程同時(shí)運(yùn)行代碼

 更新時(shí)間:2025年02月26日 08:55:02   作者:Hello.Reader  
Rust使用1:1線程模型,通過std::thread::spawn創(chuàng)建線程,返回JoinHandle用于等待線程完成,閉包默認(rèn)借用外部變量,使用move關(guān)鍵字轉(zhuǎn)移所有權(quán),多線程共享數(shù)據(jù)時(shí)需使用并發(fā)原語,如Mutex、RwLock、Arc等,以避免競態(tài)條件

一、Rust 的線程模型

Rust 標(biāo)準(zhǔn)庫使用的是 1:1 的線程模型,即每一個語言層的線程都對應(yīng)一個操作系統(tǒng)線程。Rust 中通過標(biāo)準(zhǔn)庫提供的 std::thread 模塊來創(chuàng)建、管理線程。

當(dāng)然,也有一些第三方庫會采用不同的線程模型,或者利用異步(async)機(jī)制來實(shí)現(xiàn)并發(fā)(比如 Rust 的 async/await 機(jī)制),在面對具體需求時(shí)可以根據(jù)實(shí)際情況做選擇。

二、創(chuàng)建線程:thread::spawn

要在 Rust 中創(chuàng)建一個新線程,可以使用 thread::spawn 函數(shù),并向它傳遞一個閉包(closure)。閉包中包含需要在線程中執(zhí)行的代碼。

例如:

use std::thread;
use std::time::Duration;

fn main() {
    // 使用 thread::spawn 創(chuàng)建新的線程
    thread::spawn(|| {
        for i in 1..10 {
            println!("hi number {} from the spawned thread!", i);
            thread::sleep(Duration::from_millis(1));
        }
    });

    // 主線程也執(zhí)行一些操作
    for i in 1..5 {
        println!("hi number {} from the main thread!", i);
        thread::sleep(Duration::from_millis(1));
    }
}

在上面的例子里,我們在子線程中打印數(shù)字,同時(shí)在主線程中也打印數(shù)字。由于操作系統(tǒng)會對線程進(jìn)行調(diào)度,輸出的順序無法完全預(yù)測。可能主線程先打印,也可能子線程先打印,或者兩者交錯執(zhí)行。

需要注意的是,當(dāng)主線程結(jié)束時(shí),所有通過 spawn 創(chuàng)建的子線程會被強(qiáng)制終止,即使子線程還沒有執(zhí)行完。

三、等待線程完成:JoinHandle 與 join

如果希望確保子線程的代碼一定會執(zhí)行完,那么就需要在主線程結(jié)束前等待子線程。thread::spawn 的返回值是一個 JoinHandle,可以用它來調(diào)用 join 方法,阻塞(block)當(dāng)前線程,直到對應(yīng)的子線程執(zhí)行完成。

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));
    }

    // 調(diào)用 join,阻塞主線程,直到子線程結(jié)束
    handle.join().unwrap();
}

當(dāng)我們在主線程中調(diào)用 handle.join() 時(shí),主線程會暫停執(zhí)行,直到子線程完成工作。這樣就能確保在程序退出前,所有線程都能順利完成執(zhí)行。

如果把 join 放在主線程的循環(huán)之前,那么主線程會先等待子線程結(jié)束,才會進(jìn)行自身的打印操作——這樣就不會再看到主線程與子線程的輸出交錯了。

四、move 閉包與線程

多線程編程中常常需要在線程間傳遞數(shù)據(jù)或訪問主線程中的變量。

在 Rust 中,如果一個閉包想要捕獲外部變量,就要考慮該變量的所有權(quán)或引用生命周期問題。

4.1.問題場景

如下示例所示,如果我們在主線程中創(chuàng)建一個向量 v,然后在子線程中直接打印這個向量,就會出錯:

use std::thread;

fn main() {
    let v = vec![1, 2, 3];

    let handle = thread::spawn(|| {
        println!("Here's a vector: {:?}", v);
    });

    // ...
    handle.join().unwrap();
}

編譯時(shí),Rust 會提示閉包捕獲的是對 v 的引用,但無法保證在子線程運(yùn)行時(shí) v 依舊有效:主線程可能在子線程使用 v 之前就結(jié)束了,讓 v 不再有效,從而導(dǎo)致潛在的懸垂引用(dangling reference)。

4.2.使用 move 關(guān)鍵字

為了解決這個問題,需要在閉包前面加上 move 關(guān)鍵字,這樣可以把閉包中用到的外部數(shù)據(jù)移動到閉包的所有權(quán)中。

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();
}

在這里,move 會把 v 的所有權(quán)從主線程轉(zhuǎn)移到子線程,從而保證子線程在使用 v 時(shí)不會遇到生命周期問題。不過需要注意的是,這樣一來,主線程就不能再使用 v 了,因?yàn)樗袡?quán)已經(jīng)被移動出去了。

4.3.不能與 drop 共用所有權(quán)

如果嘗試同時(shí)在主線程中顯式調(diào)用 drop(v) 并且在子線程中使用 v,無論有沒有用 move,都行不通。Rust 的所有權(quán)規(guī)則會保證同一份數(shù)據(jù)不會被多次釋放或引用到失效的數(shù)據(jù)。所以,在設(shè)計(jì)多線程邏輯時(shí),需要明確劃分?jǐn)?shù)據(jù)的所有權(quán)與生命周期,以避免死鎖、競態(tài)條件或懸垂引用等問題。

五、小結(jié)

  1. Rust 標(biāo)準(zhǔn)庫中的線程模型:Rust 使用一對一(1:1)模型,每個語言線程對應(yīng)一個系統(tǒng)線程。
  2. 創(chuàng)建線程:使用 thread::spawn 來創(chuàng)建子線程,傳入一個閉包作為要執(zhí)行的代碼。
  3. 線程同步:通過返回的 JoinHandle 調(diào)用 join,可以阻塞主線程并等待子線程完成執(zhí)行。
  4. 所有權(quán)與生命周期:使用 move 關(guān)鍵字將閉包所需的變量從主線程移動到子線程,從而避免引用沖突或無效引用。
  5. 小心共享數(shù)據(jù):當(dāng)多個線程需要同時(shí)訪問或修改同一份數(shù)據(jù)時(shí),需要使用安全的并發(fā)原語(例如 Mutex、RwLock、Arc 等),否則會出現(xiàn)競態(tài)條件。

在 Rust 中編寫并發(fā)程序時(shí),我們需要充分利用所有權(quán)與借用檢查器提供的安全保障,同時(shí)對多線程邏輯進(jìn)行精心設(shè)計(jì)。盡管多線程編程能帶來性能上的提升,但也應(yīng)關(guān)注潛在的風(fēng)險(xiǎn),并通過 Rust 的工具鏈和語言特性來盡量減少錯誤,寫出更安全、更可靠的并發(fā)應(yīng)用。

以上為個人經(jīng)驗(yàn),希望能給大家一個參考,也希望大家多多支持腳本之家。

相關(guān)文章

  • Rust使用Sled添加高性能嵌入式數(shù)據(jù)庫

    Rust使用Sled添加高性能嵌入式數(shù)據(jù)庫

    這篇文章主要為大家詳細(xì)介紹了如何在Rust項(xiàng)目中使用Sled庫,一個為Rust生態(tài)設(shè)計(jì)的現(xiàn)代、高性能嵌入式數(shù)據(jù)庫,感興趣的小伙伴可以跟隨小編一起學(xué)習(xí)一下
    2024-03-03
  • Rust中的&和ref使用解讀

    Rust中的&和ref使用解讀

    在Rust中,`&`和`ref`都可以用來定義指針,但它們的使用位置不同,`&`通常放在等號右邊,而`ref`放在左邊,`&`主要用于函數(shù)參數(shù)和模式匹配中,而`ref`主要用于模式匹配中,Rust通過`&`和`ref`提供了靈活的指針操作,使得代碼更加安全和高效
    2025-02-02
  • rust將bitmap位圖文件另存為png格式的方法

    rust將bitmap位圖文件另存為png格式的方法

    通過添加依賴,轉(zhuǎn)換函數(shù)和單元測試操作步驟來解決將bitmap位圖文件另存為png格式文件,本文通過實(shí)例代碼給大家介紹的非常詳細(xì),對rust bitmap位另存為png格式的操作方法感興趣的朋友一起看看吧
    2024-03-03
  • Rust生命周期常見誤區(qū)(中英對照)全面指南

    Rust生命周期常見誤區(qū)(中英對照)全面指南

    這篇文章主要WEIDJAI?介紹了Rust生命周期常見誤區(qū)(中英對照)的全面指南,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-11-11
  • 解讀Rust的Rc<T>:實(shí)現(xiàn)多所有權(quán)的智能指針方式

    解讀Rust的Rc<T>:實(shí)現(xiàn)多所有權(quán)的智能指針方式

    Rc<T> 是 Rust 中用于多所有權(quán)的引用計(jì)數(shù)類型,通過增加引用計(jì)數(shù)來管理共享數(shù)據(jù),只有當(dāng)最后一個引用離開作用域時(shí),數(shù)據(jù)才會被釋放,Rc<T> 適用于單線程環(huán)境,并且只允許不可變共享數(shù)據(jù);需要可變共享時(shí)應(yīng)考慮使用 RefCell<T> 或其他解決方案
    2025-02-02
  • rust多樣化錯誤處理(從零學(xué)習(xí))

    rust多樣化錯誤處理(從零學(xué)習(xí))

    一個優(yōu)秀的項(xiàng)目,錯誤處理的優(yōu)雅性是至關(guān)重要的,而rust,anyhow creat是繞不過去的一個,今天我們來研究下,怎么使用它,幫助我們寫出更優(yōu)雅的代碼,有需要的朋友可以借鑒參考下,希望能夠有所幫助
    2023-11-11
  • 探索Rust切片與Go有何區(qū)別

    探索Rust切片與Go有何區(qū)別

    這篇文章主要為大家介紹了Rust切片與Go的區(qū)別探索,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2024-01-01
  • 一文帶你了解Rust是如何處理錯誤的

    一文帶你了解Rust是如何處理錯誤的

    程序在運(yùn)行的過程中,總是會不可避免地產(chǎn)生錯誤,而如何優(yōu)雅地解決錯誤,也是語言的設(shè)計(jì)哲學(xué)之一。本文就來和大家來了Rust是如何處理錯誤的,感興趣的可以了解一下
    2022-11-11
  • Rust?HashMap詳解及單詞統(tǒng)計(jì)示例用法詳解

    Rust?HashMap詳解及單詞統(tǒng)計(jì)示例用法詳解

    HashMap在Rust中是一個強(qiáng)大的工具,通過合理使用可以簡化很多與鍵值對相關(guān)的問題,在實(shí)際開發(fā)中,我們可以充分利用其特性,提高代碼的效率和可讀性,本文將深入介紹HashMap的特性,以及通過一個單詞統(tǒng)計(jì)的例子展示其用法,感興趣的朋友一起看看吧
    2024-02-02
  • Rust的泛型、Traits與生命周期用法及說明

    Rust的泛型、Traits與生命周期用法及說明

    本文通過一個尋找列表中最大值的示例,展示了如何從重復(fù)代碼中提取函數(shù),再利用泛型實(shí)現(xiàn)代碼復(fù)用,主要步驟包括:識別重復(fù)邏輯;抽象提取;泛型應(yīng)用;進(jìn)一步擴(kuò)展,通過不斷抽象和泛化,我們不僅能減少代碼重復(fù),還能寫出更通用、健壯和可維護(hù)的代碼
    2025-02-02

最新評論