溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊(cè)×
其他方式登錄
點(diǎn)擊 登錄注冊(cè) 即表示同意《億速云用戶(hù)服務(wù)條款》

Arc在Rust中是怎么工作的

發(fā)布時(shí)間:2021-12-22 13:53:10 來(lái)源:億速云 閱讀:104 作者:柒染 欄目:云計(jì)算

這篇文章給大家介紹Arc在Rust中是怎么工作的,內(nèi)容非常詳細(xì),感興趣的小伙伴們可以參考借鑒,希望對(duì)大家能有所幫助。

  原子引用計(jì)數(shù)(Arc)類(lèi)型是一種智能指針,它能夠讓你以線程安全的方式在線程間共享不可變數(shù)據(jù)。我還沒(méi)有發(fā)現(xiàn)能夠很好地解釋它的工作原理的文章,所以我決定嘗試來(lái)寫(xiě)一篇。

第一部分是介紹怎樣使用Arc和為什么要使用Arc;如果你已經(jīng)了解這部分內(nèi)容,只是想知道它是如何工作的,可以直接跳到第二部分:“它是怎樣工作的(How does it work)”。

  為什么你需要使用Arc?當(dāng)你試圖在線程間共享數(shù)據(jù)時(shí),需要Arc類(lèi)型來(lái)保證被共享的類(lèi)型的生命周期,與運(yùn)行時(shí)間最長(zhǎng)的線程活得一樣久??紤]下面的例子:

  use std::thread;use std::time::Duration;fn main() { let foo = vec![0]; 

// creation of foo here thread::spawn(|| { 

thread::sleep(Duration::from_millis(20)); println!("{:?}", &foo); });} 

// foo gets dropped here

// wait 20 milliseconds

// try to print foo

  這段代碼無(wú)法編譯通過(guò)。我們會(huì)得到一個(gè)錯(cuò)誤,稱(chēng)foo的引用活得比f(wàn)oo自身更久。這是因?yàn)閒oo在main函數(shù)結(jié)尾處就被丟棄(drop)了,并且這個(gè)被丟棄的值會(huì)在20毫秒后在生成的線程中被試圖訪問(wèn)。這就是Arc的作用所在。原子引用計(jì)數(shù)確保在對(duì)foo類(lèi)型的所有引用都結(jié)束之前,它不會(huì)被丟棄——因此即使在main函數(shù)結(jié)束之后,foo仍然會(huì)存在。現(xiàn)在考慮下面的示例:

  use std::thread;use std::sync::Arc;use std::time::Duration;fn main() { 

let foo = Arc::new(vec![0]); let bar = Arc::clone(&foo); 

thread::spawn(move || { 

thread::sleep(Duration::from_millis(20)); println!("{:?}", *bar); });

 println!("{:?}", foo);}

  在這個(gè)例子中,我們可以在(主)線程中引用foo并且還可以在(子)線程被生成之后訪問(wèn)它的值。

  它是怎樣工作的?你已經(jīng)知道如何使用Arc了,現(xiàn)在讓我們討論一下它是如何工作的。當(dāng)你調(diào)用let foo = Arc::new(vec![0])時(shí),你同時(shí)創(chuàng)建了一個(gè)vec![0]和一個(gè)值為1的原子引用計(jì)數(shù),并且把它們都存儲(chǔ)在堆上的相同位置(緊挨著)。指向堆上的這份數(shù)據(jù)的指針存放在foo中。因此,foo是由指向一個(gè)對(duì)象的指針構(gòu)成,被指向的對(duì)象包含vec![0]和原子計(jì)數(shù)。

  當(dāng)你調(diào)用let bar = Arc::clone(&foo)時(shí),你是在獲取foo的一個(gè)引用、對(duì)foo(指向存放在堆上的數(shù)據(jù)的指針)解引用、接著找到foo指向的地址、找出里面存放的值(vec![0]和原子計(jì)數(shù))、把原子計(jì)數(shù)加一、最后把指向vec![0]的指針保存在bar中。

  當(dāng)foo或bar離開(kāi)作用域時(shí),Arc::drop()就被調(diào)用了,原子計(jì)數(shù)減一。如果Arc::drop()發(fā)現(xiàn)原子計(jì)數(shù)等于0,那么它所指向的堆上的數(shù)據(jù)(vec![0]和原子計(jì)數(shù))會(huì)被清理并從堆上擦除。

  原子計(jì)數(shù)是一種能夠讓你以線程安全的方式修改和增加它的值的類(lèi)型;在對(duì)原子類(lèi)型允許進(jìn)行其他操作之前,前面的原子類(lèi)型操作必須要全部完成;因此被稱(chēng)為原子的(atomic)(即不可分割的)(操作)。

  需要注意的是,Arc只能包含不可變數(shù)據(jù)。這是因?yàn)槿绻麅蓚€(gè)線程試圖在同一時(shí)間修改被包含的值,Arc無(wú)法保證避免數(shù)據(jù)競(jìng)爭(zhēng)。如果你希望修改數(shù)據(jù),你應(yīng)該在Arc類(lèi)型內(nèi)部封裝一個(gè)互斥鎖保護(hù)(Mutex guard)。

  為什么這些東西能讓Arc是線程安全的呢?Arc是線程安全的是因?yàn)樗o編譯器保證數(shù)據(jù)的引用至少活得和數(shù)據(jù)本身一樣長(zhǎng)(譯注:這里原作者應(yīng)該是想表達(dá),數(shù)據(jù)的引用存在期間,數(shù)據(jù)都是有效的)。這是因?yàn)槊看文銊?chuàng)建一個(gè)對(duì)堆上數(shù)據(jù)得引用,原子計(jì)數(shù)就會(huì)加一,數(shù)據(jù)只有在當(dāng)原子計(jì)數(shù)等于零得時(shí)候才會(huì)被丟棄(每當(dāng)一個(gè)引用離開(kāi)作用域時(shí),原子計(jì)數(shù)會(huì)減一)——Arc和一個(gè)普通得Rc(引用計(jì)數(shù))之間得區(qū)別就在于原子計(jì)數(shù)。

關(guān)于Arc在Rust中是怎么工作的就分享到這里了,希望以上內(nèi)容可以對(duì)大家有一定的幫助,可以學(xué)到更多知識(shí)。如果覺(jué)得文章不錯(cuò),可以把它分享出去讓更多的人看到。

向AI問(wèn)一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI