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

rust使用Atomic創(chuàng)建全局變量和使用操作方法

 更新時間:2024年05月05日 11:24:09   作者:1024小神  
從 Rust1.34 版本后,就正式支持原子類型,原子指的是一系列不可被 CPU 上下文交換的機器指令,這些指令組合在一起就形成了原子操作,這篇文章主要介紹了rust使用Atomic創(chuàng)建全局變量和使用,需要的朋友可以參考下

Mutex用起來簡單,但是無法并發(fā)讀,RwLock可以并發(fā)讀,但是使用場景較為受限且性能不夠,那么有沒有一種全能性選手呢? 歡迎我們的Atomic閃亮登場。

從 Rust1.34 版本后,就正式支持原子類型。原子指的是一系列不可被 CPU 上下文交換的機器指令,這些指令組合在一起就形成了原子操作。在多核 CPU 下,當(dāng)某個 CPU 核心開始運行原子操作時,會先暫停其它 CPU 內(nèi)核對內(nèi)存的操作,以保證原子操作不會被其它 CPU 內(nèi)核所干擾。

由于原子操作是通過指令提供的支持,因此它的性能相比鎖和消息傳遞會好很多。相比較于鎖而言,原子類型不需要開發(fā)者處理加鎖和釋放鎖的問題,同時支持修改,讀取等操作,還具備較高的并發(fā)性能,幾乎所有的語言都支持原子類型。

可以看出原子類型是無鎖類型,但是無鎖不代表無需等待,因為原子類型內(nèi)部使用了CAS循環(huán),當(dāng)大量的沖突發(fā)生時,該等待還是得等待!但是總歸比鎖要好。

CAS 全稱是 Compare and swap, 它通過一條指令讀取指定的內(nèi)存地址,然后判斷其中的值是否等于給定的前置值,如果相等,則將其修改為新的值

原子類型的一個常用場景,就是作為全局變量來使用:

use std::sync::atomic::{AtomicI32, Ordering};
use std::thread::{self, JoinHandle};
static R: AtomicI32 = AtomicI32::new(0);
fn thread_add() {
    // 多個線程修改全局變量
    for i in 0..1000 {
        R.fetch_add(1, Ordering::Relaxed);
    }
}
fn main() {
    // This will POST a body of `foo=bar&baz=quux`
    let mut init_data = vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
    let mut hand_list = Vec::with_capacity(init_data.len());
    for i in init_data {
        hand_list.push(thread::spawn(thread_add));
    }
    for h in hand_list {
        h.join().unwrap();
    }
    let r_value = R.load(Ordering::Relaxed);
    println!("全局變量最后的值是: {r_value:?}");
}

并且能夠保證數(shù)據(jù)讀寫不出錯:

以上代碼啟動了數(shù)個線程,每個線程都在瘋狂對全局變量進行加 1 操作, 最后將它與線程數(shù) * 加1次數(shù)進行比較,如果發(fā)生了因為多個線程同時修改導(dǎo)致了臟數(shù)據(jù),那么這兩個必將不相等。好在,它沒有讓我們失望,不僅快速的完成了任務(wù),而且保證了 100%的并發(fā)安全性。

當(dāng)然以上代碼的功能其實也可以通過Mutex來實現(xiàn),但是后者的強大功能是建立在額外的性能損耗基礎(chǔ)上的,因此性能會遜色不少:

Atomic實現(xiàn):673ms Mutex實現(xiàn): 1136ms

可以看到Atomic實現(xiàn)會比Mutex41%,實際上在復(fù)雜場景下還能更快(甚至達到 4 倍的性能差距)!

還有一點值得注意: 和Mutex一樣,Atomic的值具有內(nèi)部可變性,你無需將其聲明為mut

use std::sync::Mutex;
use std::sync::atomic::{Ordering, AtomicU64};
struct Counter {
    count: u64
}
fn main() {
    let n = Mutex::new(Counter {
        count: 0
    });
    n.lock().unwrap().count += 1;
    let n = AtomicU64::new(0);
    n.fetch_add(0, Ordering::Relaxed);
}

這里有一個奇怪的枚舉成員Ordering::Relaxed, 看上去很像是排序作用,但是我們并沒有做排序操作???實際上它用于控制原子操作使用的內(nèi)存順序

內(nèi)存順序

內(nèi)存順序是指 CPU 在訪問內(nèi)存時的順序,該順序可能受以下因素的影響:

代碼中的先后順序

編譯器優(yōu)化導(dǎo)致在編譯階段發(fā)生改變(內(nèi)存重排序 reordering)
運行階段因 CPU 的緩存機制導(dǎo)致順序被打亂

限定內(nèi)存順序的 5 個規(guī)則:

在理解了內(nèi)存順序可能存在的改變后,你就可以明白為什么 Rust 提供了Ordering::Relaxed用于限定內(nèi)存順序了,事實上,該枚舉有 5 個成員:

Relaxed, 這是最寬松的規(guī)則,它對編譯器和 CPU 不做任何限制,可以亂序。
Release 釋放,設(shè)定內(nèi)存屏障(Memory barrier),保證它之前的操作永遠在它之前,但是它后面的操作可能被重排到它前面。
Acquire 獲取, 設(shè)定內(nèi)存屏障,保證在它之后的訪問永遠在它之后,但是它之前的操作卻有可能被重排到它后面,往往和Release在不同線程中聯(lián)合使用。
AcqRel, 是 Acquire 和 Release 的結(jié)合,同時擁有它們倆提供的保證。比如你要對一個 atomic 自增 1,同時希望該操作之前和之后的讀取或?qū)懭氩僮鞑粫恢匦屡判颉?br />SeqCst 順序一致性, SeqCst就像是AcqRel的加強版,它不管原子操作是屬于讀取還是寫入的操作,只要某個線程有用到SeqCst的原子操作,線程中該SeqCst操作前的數(shù)據(jù)操作絕對不會被重新排在該SeqCst操作之后,且該SeqCst操作后的數(shù)據(jù)操作也絕對不會被重新排在SeqCst操作前。
這些規(guī)則由于是系統(tǒng)提供的,因此其它語言提供的相應(yīng)規(guī)則也大同小異,大家如果不明白可以看看其它語言的相關(guān)解釋。

Atomic 能替代鎖嗎

那么原子類型既然這么全能,它可以替代鎖嗎?答案是不行:

對于復(fù)雜的場景下,鎖的使用簡單粗暴,不容易有坑
std::sync::atomic包中僅提供了數(shù)值類型的原子操作:AtomicBool, AtomicIsize, AtomicUsize, AtomicI8, AtomicU16等,而鎖可以應(yīng)用于各種類型
在有些情況下,必須使用鎖來配合,例如上一章節(jié)中使用Mutex配合Condvar

Atomic 的應(yīng)用場景

事實上,Atomic雖然對于用戶不太常用,但是對于高性能庫的開發(fā)者、標(biāo)準(zhǔn)庫開發(fā)者都非常常用,它是并發(fā)原語的基石,除此之外,還有一些場景適用:

無鎖(lock free)數(shù)據(jù)結(jié)構(gòu)
全局變量,例如全局自增 ID, 在后續(xù)章節(jié)會介紹
跨線程計數(shù)器,例如可以用于統(tǒng)計指標(biāo)
以上列出的只是Atomic適用的部分場景,具體場景需要大家未來根據(jù)自己的需求進行權(quán)衡選擇。

到此這篇關(guān)于rust使用Atomic創(chuàng)建全局變量和使用的文章就介紹到這了,更多相關(guān)rust創(chuàng)建全局變量內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • 詳解Rust中的所有權(quán)機制

    詳解Rust中的所有權(quán)機制

    Rust?語言提供了跟其他系統(tǒng)編程語言相同的方式來控制你使用的內(nèi)存,但擁有數(shù)據(jù)所有者在離開作用域后自動清除其數(shù)據(jù)的功能意味著你無須額外編寫和調(diào)試相關(guān)的控制代碼,這篇文章主要介紹了Rust中的所有權(quán)機制,需要的朋友可以參考下
    2022-10-10
  • Rust中實例化動態(tài)對象的示例詳解

    Rust中實例化動態(tài)對象的示例詳解

    這篇文章主要為大家詳細(xì)介紹了Rust中實例化動態(tài)對象的多種方法,文中的示例代碼講解詳細(xì),感興趣的小伙伴可以跟隨小編一起學(xué)習(xí)一下
    2025-02-02
  • Rust中的關(guān)聯(lián)類型總結(jié)

    Rust中的關(guān)聯(lián)類型總結(jié)

    關(guān)聯(lián)類型是定義通用trait的一種機制。它允許在trait中定義一個或多個占位符類型,這些類型將在trait的實現(xiàn)中具體化。文中有詳細(xì)示例代碼供參考,需要的朋友可以閱讀一下
    2023-05-05
  • Rust語言之Prometheus系統(tǒng)監(jiān)控工具包的使用詳解

    Rust語言之Prometheus系統(tǒng)監(jiān)控工具包的使用詳解

    Prometheus?是一個開源的系統(tǒng)監(jiān)控和警報工具包,最初是由SoundCloud構(gòu)建的,隨著時間的發(fā)展,Prometheus已經(jīng)具有適用于各種使用場景的版本,為了開發(fā)者方便開發(fā),更是有各種語言版本的Prometheus的開發(fā)工具包,本文主要介紹Rust版本的Prometheus開發(fā)工具包
    2023-10-10
  • Rust調(diào)用C程序的實現(xiàn)步驟

    Rust調(diào)用C程序的實現(xiàn)步驟

    本文主要介紹了Rust調(diào)用C程序的實現(xiàn)步驟,包括創(chuàng)建C函數(shù)、編譯C代碼、鏈接Rust和C代碼等步驟,具有一定的參考價值,感興趣的可以了解一下
    2023-12-12
  • Rust語言數(shù)據(jù)類型的具體使用

    Rust語言數(shù)據(jù)類型的具體使用

    在Rust中,每個值都有一個明確的數(shù)據(jù)類型,本文主要介紹了Rust語言數(shù)據(jù)類型的具體使用,具有一定的參考價值,感興趣的可以了解一下
    2024-04-04
  • Rust Aya 框架編寫 eBPF 程序

    Rust Aya 框架編寫 eBPF 程序

    這篇文章主要介紹了Rust Aya 框架編寫 eBPF 程序方法的相關(guān)資料,需要的朋友可以參考下
    2022-11-11
  • 解析Rust?struct?中的生命周期

    解析Rust?struct?中的生命周期

    rust?的生命周期保證了內(nèi)存的安全性,同時也增加了開發(fā)者的心智負(fù)擔(dān)。是在上線之前多費心思寫代碼,還是在上線以后忙忙活活查問題,這是個?trade?off?問題,這篇文章主要介紹了Rust?struct?中的生命周期,需要的朋友可以參考下
    2022-10-10
  • Rust 累計時間長度的操作方法

    Rust 累計時間長度的操作方法

    在Rust中,如果你想要記錄累計時間,通常可以使用標(biāo)準(zhǔn)庫中的std::time::Duration類型,這篇文章主要介紹了Rust如何累計時間長度,需要的朋友可以參考下
    2024-05-05
  • Rust中的不安全代碼詳解

    Rust中的不安全代碼詳解

    這篇文章主要為大家介紹了Rust中的不安全代碼詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2023-04-04

最新評論