中文亚洲精品无码_熟女乱子伦免费_人人超碰人人爱国产_亚洲熟妇女综合网

當(dāng)前位置: 首頁(yè) > news >正文

深圳做網(wǎng)站知名排行發(fā)廣告平臺(tái)有哪些免費(fèi)

深圳做網(wǎng)站知名排行,發(fā)廣告平臺(tái)有哪些免費(fèi),東莞優(yōu)化網(wǎng)站建設(shè),嘉興建站網(wǎng)站模板安全且高效地處理并發(fā)編程是 Rust 的另一個(gè)主要目標(biāo)。并發(fā)編程(Concurrent programming),代表程序的不同部分相互獨(dú)立地執(zhí)行,而并行編程(parallel programming)代表程序不同部分同時(shí)執(zhí)行,這兩個(gè)…

安全且高效地處理并發(fā)編程是 Rust 的另一個(gè)主要目標(biāo)。并發(fā)編程(Concurrent programming),代表程序的不同部分相互獨(dú)立地執(zhí)行,而并行編程(parallel programming)代表程序不同部分同時(shí)執(zhí)行,這兩個(gè)概念隨著計(jì)算機(jī)越來(lái)越多的利用多處理器的優(yōu)勢(shì)而顯得愈發(fā)重要。由于歷史原因,在此類上下文中編程一直是困難且容易出錯(cuò)的:Rust 希望能改變這一點(diǎn)。

起初,Rust 團(tuán)隊(duì)認(rèn)為確保內(nèi)存安全和防止并發(fā)問(wèn)題是兩個(gè)分別需要不同方法應(yīng)對(duì)的挑戰(zhàn)。隨著時(shí)間的推移,團(tuán)隊(duì)發(fā)現(xiàn)所有權(quán)和類型系統(tǒng)是一系列解決內(nèi)存安全和并發(fā)問(wèn)題的強(qiáng)有力的工具!通過(guò)利用所有權(quán)和類型檢查,在 Rust 中很多并發(fā)錯(cuò)誤都是編譯時(shí)錯(cuò)誤,而非運(yùn)行時(shí)錯(cuò)誤。因此,相比花費(fèi)大量時(shí)間嘗試重現(xiàn)運(yùn)行時(shí)并發(fā) bug 出現(xiàn)的特定情況,Rust 會(huì)拒絕編譯不正確的代碼并提供解釋問(wèn)題的錯(cuò)誤信息。因此,你可以在開(kāi)發(fā)時(shí)修復(fù)代碼,而不是在部署到生產(chǎn)環(huán)境后修復(fù)代碼。

一、線程

在大部分現(xiàn)代操作系統(tǒng)中,已執(zhí)行程序的代碼在一個(gè)進(jìn)程(process)中運(yùn)行,操作系統(tǒng)則會(huì)負(fù)責(zé)管理多個(gè)進(jìn)程。在程序內(nèi)部,也可以擁有多個(gè)同時(shí)運(yùn)行的獨(dú)立部分。這些運(yùn)行這些獨(dú)立部分的功能被稱為線程(threads)。

將程序中的計(jì)算拆分進(jìn)多個(gè)線程可以改善性能,因?yàn)槌绦蚩梢酝瑫r(shí)進(jìn)行多個(gè)任務(wù),不過(guò)這也會(huì)增加復(fù)雜性。因?yàn)榫€程是同時(shí)運(yùn)行的,所以無(wú)法預(yù)先保證不同線程中的代碼的執(zhí)行順序。這會(huì)導(dǎo)致諸如此類的問(wèn)題:

  • 競(jìng)態(tài)條件(Race conditions),多個(gè)線程以不一致的順序訪問(wèn)數(shù)據(jù)或資源
  • 死鎖(Deadlocks),兩個(gè)線程相互等待對(duì)方,這會(huì)阻止兩者繼續(xù)運(yùn)行
  • 只會(huì)發(fā)生在特定情況且難以穩(wěn)定重現(xiàn)和修復(fù)的 bug

Rust 嘗試減輕使用線程的負(fù)面影響。不過(guò)在多線程上下文中編程仍需格外小心,同時(shí)其所要求的代碼結(jié)構(gòu)也不同于運(yùn)行于單線程的程序。

編程語(yǔ)言有一些不同的方法來(lái)實(shí)現(xiàn)線程,而且很多操作系統(tǒng)提供了創(chuàng)建新線程的 API。Rust 標(biāo)準(zhǔn)庫(kù)使用 1:1 線程實(shí)現(xiàn),這代表程序的每一個(gè)語(yǔ)言級(jí)線程使用一個(gè)系統(tǒng)線程。

在 Rust 中,你可以使用 std::thread::spawn 來(lái)創(chuàng)建多個(gè)線程。以下是一個(gè)創(chuàng)建多個(gè)線程并讓它們執(zhí)行不同任務(wù)的例子:

use std::thread;
use std::time::Duration;fn main() {// 創(chuàng)建一個(gè)向量來(lái)存儲(chǔ)JoinHandlelet mut handles: Vec<thread::JoinHandle<()>> = Vec::new();// 創(chuàng)建并啟動(dòng)多個(gè)線程for i in 0..5 {let handle = thread::spawn(move || {// 打印線程編號(hào)println!("Thread number {} is running", i);// 模擬一些工作thread::sleep(Duration::from_millis(500 * i));// 打印線程完成的消息println!("Thread number {} finished", i);});// 將JoinHandle存儲(chǔ)在向量中handles.push(handle);}// 等待所有線程結(jié)束for handle in handles {handle.join().unwrap();}println!("All threads have finished execution.");
}

在這個(gè)例子中,我們首先創(chuàng)建了一個(gè) Vec<thread::JoinHandle<()>> 來(lái)存儲(chǔ)每個(gè)線程的 JoinHandle。然后,我們使用一個(gè) for 循環(huán)來(lái)創(chuàng)建 5 個(gè)線程。每個(gè)線程都執(zhí)行一個(gè)移動(dòng)(move)閉包,該閉包打印線程編號(hào),休眠一段時(shí)間,然后打印完成消息。移動(dòng)閉包通過(guò) move 關(guān)鍵字捕獲循環(huán)變量 i 的值,使得每個(gè)線程都有自己的 i 副本。

在所有線程創(chuàng)建之后,我們遍歷 handles 向量,調(diào)用每個(gè) JoinHandlejoin 方法。這會(huì)阻塞主線程直到對(duì)應(yīng)的線程結(jié)束。如果線程成功結(jié)束,join 方法會(huì)返回 ()。如果線程由于 panic 而結(jié)束,join 方法會(huì)返回一個(gè)錯(cuò)誤,這里我們使用 unwrap 來(lái)獲取結(jié)果并忽略潛在的錯(cuò)誤。最后,當(dāng)所有線程都完成后,我們?cè)谥骶€程中打印一條消息。

請(qǐng)注意,在實(shí)際應(yīng)用中,你可能需要更細(xì)致地處理 join 方法返回的結(jié)果,以確保能夠適當(dāng)?shù)仨憫?yīng)線程中的 panic。

二、消息傳遞

一個(gè)日益流行的確保安全并發(fā)的方式是消息傳遞(message passing),這里線程或 actor 通過(guò)發(fā)送包含數(shù)據(jù)的消息來(lái)相互溝通。這個(gè)思想來(lái)源于 Go 編程語(yǔ)言文檔中 的口號(hào):“不要通過(guò)共享內(nèi)存來(lái)通訊;而是通過(guò)通訊來(lái)共享內(nèi)存”。

為了實(shí)現(xiàn)消息傳遞并發(fā),Rust 標(biāo)準(zhǔn)庫(kù)提供了一個(gè)信道(channel)實(shí)現(xiàn)。信道是一個(gè)通用編程概念,表示數(shù)據(jù)從一個(gè)線程發(fā)送到另一個(gè)線程。編程中的信息渠道(信道)有兩部分組成,一個(gè)發(fā)送者(transmitter)和一個(gè)接收者(receiver)。代碼中的一部分調(diào)用發(fā)送者的方法以及希望發(fā)送的數(shù)據(jù),另一部分則檢查接收端收到的消息。當(dāng)發(fā)送者或接收者任一被丟棄時(shí)可以認(rèn)為信道被關(guān)閉(closed)了。

mpsc::channel 函數(shù)創(chuàng)建一個(gè)新的信道;mpsc 是多個(gè)生產(chǎn)者,單個(gè)消費(fèi)者(multiple producer, single consumer)的縮寫(xiě)。簡(jiǎn)而言之,Rust 標(biāo)準(zhǔn)庫(kù)實(shí)現(xiàn)信道的方式意味著一個(gè)信道可以有多個(gè)產(chǎn)生值的發(fā)送(sending)端,但只能有一個(gè)消費(fèi)這些值的接收(receiving)端。

mpsc::channel 函數(shù)返回一個(gè)元組:第一個(gè)元素是發(fā)送端,而第二個(gè)元素是接收端。由于歷史原因,txrx 通常作為發(fā)送者(transmitter)和接收者(receiver)的縮寫(xiě)。

信道的發(fā)送端有一個(gè) send 方法用來(lái)獲取需要放入信道的值。send 方法返回一個(gè) Result<T, E> 類型,所以如果接收端已經(jīng)被丟棄了,將沒(méi)有發(fā)送值的目標(biāo),所以發(fā)送操作會(huì)返回錯(cuò)誤。

信道的接收者有兩個(gè)有用的方法:recvtry_recv。 recvreceive 的縮寫(xiě)。這個(gè)方法會(huì)阻塞線程執(zhí)行直到從信道中接收一個(gè)值。一旦發(fā)送了一個(gè)值,recv 會(huì)在一個(gè) Result<T, E> 中返回它。當(dāng)信道發(fā)送端關(guān)閉,recv 會(huì)返回一個(gè)錯(cuò)誤表明不會(huì)再有新的值到來(lái)了。

try_recv 不會(huì)阻塞,相反它立刻返回一個(gè) Result<T, E>Ok 值包含可用的信息,而 Err 值代表此時(shí)沒(méi)有任何消息。如果線程在等待消息過(guò)程中還有其他工作時(shí)使用 try_recv 很有用:可以編寫(xiě)一個(gè)循環(huán)來(lái)頻繁調(diào)用 try_recv,在有可用消息時(shí)進(jìn)行處理,其余時(shí)候則處理一會(huì)其他工作直到再次檢查。

2.1 信道與所有權(quán)轉(zhuǎn)移

這里嘗試在通過(guò) tx.send 發(fā)送 data 到信道中之后將其打印出來(lái)。允許這么做是一個(gè)壞主意:一旦將值發(fā)送到另一個(gè)線程后,那個(gè)線程可能會(huì)在我們?cè)俅问褂盟熬蛯⑵湫薷幕蛘邅G棄。其他線程對(duì)值可能的修改會(huì)由于不一致或不存在的數(shù)據(jù)而導(dǎo)致錯(cuò)誤或意外的結(jié)果。

use std::sync::mpsc;
use std::thread;fn main() {let (tx, rx) = mpsc::channel();let sender_thread = thread::spawn(move || {let data = "Hello from sender!".to_string();tx.send(data).unwrap();println!("Sended: {}", data);});let receiver_thread = thread::spawn(move || {let received = rx.recv().unwrap();println!("Received: {}", received);});sender_thread.join().unwrap();receiver_thread.join().unwrap();
}

編譯這一段代碼會(huì)報(bào)錯(cuò):

   Compiling playground v0.0.1 (/playground)
error[E0382]: borrow of moved value: `data`--> src/main.rs:10:32|
8  |         let data = "Hello from sender!".to_string();|             ---- move occurs because `data` has type `String`, which does not implement the `Copy` trait
9  |         tx.send(data).unwrap();|                 ---- value moved here
10 |         println!("Sended: {}", data);|                                ^^^^ value borrowed here after move|= note: this error originates in the macro `$crate::format_args_nl` which comes from the expansion of the macro `println` (in Nightly builds, run with -Z macro-backtrace for more info)For more information about this error, try `rustc --explain E0382`.
error: could not compile `playground` (bin "playground") due to 1 previous error

我們的并發(fā)錯(cuò)誤會(huì)造成一個(gè)編譯時(shí)錯(cuò)誤。send 函數(shù)獲取其參數(shù)的所有權(quán)并移動(dòng)這個(gè)值歸接收者所有。這可以防止在發(fā)送后再次意外地使用這個(gè)值;所有權(quán)系統(tǒng)檢查一切是否合乎規(guī)則。

修正這段代碼,就是把 tx.send 之后的打印語(yǔ)句去除,程序就可以正常運(yùn)行了。

use std::sync::mpsc;
use std::thread;fn main() {let (tx, rx) = mpsc::channel();let sender_thread = thread::spawn(move || {let data = "Hello from sender!".to_string();tx.send(data).unwrap();});let receiver_thread = thread::spawn(move || {let received = rx.recv().unwrap();println!("Received: {}", received);});sender_thread.join().unwrap();receiver_thread.join().unwrap();
}

運(yùn)行結(jié)果

Received: Hello from sender!

在這個(gè)示例中,我們創(chuàng)建了一個(gè)信道 (tx, rx)tx 是發(fā)送端,rx 是接收端。我們創(chuàng)建了一個(gè)線程 sender_thread 來(lái)發(fā)送數(shù)據(jù),并將數(shù)據(jù)的所有權(quán)通過(guò) send 方法轉(zhuǎn)移給接收端。接收端通過(guò) recv 方法接收數(shù)據(jù)。

2.2 發(fā)送多個(gè)值并觀察接收者的等待

use std::sync::mpsc;
use std::thread;fn main() {let (tx, rx) = mpsc::channel();// 創(chuàng)建一個(gè)線程發(fā)送多個(gè)值let sender_thread = thread::spawn(move || {for i in 1..=5 {tx.send(i).unwrap();println!("Sent {}", i);}});// 創(chuàng)建一個(gè)線程接收值let receiver_thread = thread::spawn(move || {for _ in 1..=5 {let received = rx.recv().unwrap();println!("Received {}", received);}});sender_thread.join().unwrap();receiver_thread.join().unwrap();
}

運(yùn)行結(jié)果

Sent 1
Sent 2
Sent 3
Sent 4
Sent 5
Received 1
Received 2
Received 3
Received 4
Received 5

在這個(gè)示例中,我們創(chuàng)建了一個(gè)線程發(fā)送一系列值(1 到 5),并在發(fā)送每個(gè)值后打印一條消息。接收端在接收到所有值之前會(huì)阻塞等待。

2.3 通過(guò)克隆發(fā)送者來(lái)創(chuàng)建多個(gè)生產(chǎn)者

use std::sync::mpsc;
use std::thread;fn main() {let (tx, rx) = mpsc::channel();// 克隆發(fā)送端以創(chuàng)建多個(gè)生產(chǎn)者let tx_clone = tx.clone();let sender_thread1 = thread::spawn(move || {for i in 1..=5 {tx.send(i).unwrap();println!("Sender 1 sent {}", i);}});let sender_thread2 = thread::spawn(move || {for i in 5..=10 {tx_clone.send(i).unwrap();println!("Sender 2 sent {}", i);}});// 接收端let receiver_thread = thread::spawn(move || {let mut values = Vec::new();for _ in 1..=10 {values.push(rx.recv().unwrap());}println!("Received all values: {:?}", values);});sender_thread1.join().unwrap();sender_thread2.join().unwrap();receiver_thread.join().unwrap();
}

運(yùn)行結(jié)果

Sender 1 sent 1
Sender 1 sent 2
Sender 2 sent 5
Sender 2 sent 6
Sender 2 sent 7
Sender 2 sent 8
Sender 2 sent 9
Sender 2 sent 10
Sender 1 sent 3
Sender 1 sent 4
Sender 1 sent 5
Received all values: [1, 5, 2, 6, 7, 8, 9, 10, 3, 4]

在這個(gè)示例中,我們克隆了發(fā)送端 tx 來(lái)創(chuàng)建兩個(gè)生產(chǎn)者 sender_thread1sender_thread2。每個(gè)生產(chǎn)者都發(fā)送一系列值,而接收端接收所有值并將它們存儲(chǔ)在一個(gè)向量中。

請(qǐng)注意,在實(shí)際應(yīng)用中,你可能需要考慮使用更高級(jí)的并發(fā)原語(yǔ),如 std::sync::Arc 來(lái)共享狀態(tài),或者使用 std::sync::Barrier 來(lái)同步線程。此外,錯(cuò)誤處理在多線程程序中也非常重要,這里為了示例的簡(jiǎn)潔性,我們使用了 unwrap 來(lái)處理可能的錯(cuò)誤。在生產(chǎn)代碼中,你應(yīng)該更細(xì)致地處理這些情況。

三、共享狀態(tài)

在某種程度上,任何編程語(yǔ)言中的信道都類似于單所有權(quán),因?yàn)橐坏⒁粋€(gè)值傳送到信道中,將無(wú)法再使用這個(gè)值。共享內(nèi)存類似于多所有權(quán):多個(gè)線程可以同時(shí)訪問(wèn)相同的內(nèi)存位置。

互斥鎖

互斥鎖(mutex)是 mutual exclusion 的縮寫(xiě),也就是說(shuō),任意時(shí)刻,其只允許一個(gè)線程訪問(wèn)某些數(shù)據(jù)。為了訪問(wèn)互斥鎖中的數(shù)據(jù),線程首先需要通過(guò)獲取互斥鎖的鎖(lock)來(lái)表明其希望訪問(wèn)數(shù)據(jù)。鎖是一個(gè)作為互斥鎖一部分的數(shù)據(jù)結(jié)構(gòu),它記錄誰(shuí)有數(shù)據(jù)的排他訪問(wèn)權(quán)。因此,我們描述互斥鎖為通過(guò)鎖系統(tǒng)保護(hù)(guarding)其數(shù)據(jù)。

互斥鎖以難以使用著稱,因?yàn)槟悴坏貌挥涀?#xff1a;

  1. 在使用數(shù)據(jù)之前嘗試獲取鎖。
  2. 處理完被互斥鎖所保護(hù)的數(shù)據(jù)之后,必須解鎖數(shù)據(jù),這樣其他線程才能夠獲取鎖。

正確的管理互斥鎖異常復(fù)雜,這也是許多人之所以熱衷于信道的原因。然而,在 Rust 中,得益于類型系統(tǒng)和所有權(quán),我們不會(huì)在鎖和解鎖上出錯(cuò)。

Mutex<T>std::sync 模塊提供的一種同步原語(yǔ),用于在多線程環(huán)境中保護(hù)共享數(shù)據(jù)。Mutex<T> 代表互斥鎖(Mutex),它允許你以線程安全的方式對(duì)數(shù)據(jù)進(jìn)行訪問(wèn)。以下是 Mutex<T> 的 API 詳細(xì)介紹:

構(gòu)造函數(shù)

  • Mutex::new(data: T): 創(chuàng)建一個(gè)新的 Mutex,并將 data 作為內(nèi)部數(shù)據(jù)。

方法

  • lock(): 獲取互斥鎖,返回一個(gè)可變引用 MutexGuard。如果鎖當(dāng)前被其他線程持有,則當(dāng)前線程將阻塞,直到鎖被釋放。
  • try_lock(): 嘗試獲取互斥鎖,如果成功則返回 Some(MutexGuard),如果失敗(鎖已被其他線程持有)則返回 None,不會(huì)阻塞當(dāng)前線程。
  • get_mut(): 返回對(duì)內(nèi)部可變數(shù)據(jù)的可變引用。這個(gè)方法需要 Mutex 已經(jīng)獲得鎖,通常在使用 locktry_lock 之后使用。
  • into_inner(): 消耗 Mutex 并返回內(nèi)部數(shù)據(jù)。這個(gè)方法只有在 Mutex 沒(méi)有被鎖定的情況下才能成功使用,否則會(huì) panic。

實(shí)例方法

  • is_poisoned(): 檢查互斥鎖是否處于“中毒”狀態(tài)。如果一個(gè)線程在持有互斥鎖時(shí) panic,那么鎖將進(jìn)入中毒狀態(tài)。其他線程在嘗試獲取這個(gè)鎖時(shí)會(huì)收到一個(gè) PoisonError。
  • unlock(): 釋放互斥鎖。通常,互斥鎖會(huì)在 MutexGuard 離開(kāi)作用域時(shí)自動(dòng)釋放,但在某些情況下,你可能需要手動(dòng)釋放鎖。

類型

  • MutexGuard<'a, T>: 表示對(duì)互斥鎖的鎖定訪問(wèn)。它是通過(guò)調(diào)用 locktry_lock 獲得的。當(dāng) MutexGuard 離開(kāi)作用域時(shí),互斥鎖會(huì)自動(dòng)釋放。

錯(cuò)誤處理

  • PoisonError<T>: 當(dāng)互斥鎖中毒時(shí),locktry_lock 方法會(huì)返回這個(gè)錯(cuò)誤。它包含內(nèi)部數(shù)據(jù)的一個(gè)可變引用,允許你安全地處理中毒情況。

當(dāng)然,這里有一個(gè)使用 Mutex<T> 的 Rust 程序示例,它演示了如何在多個(gè)線程之間共享和修改數(shù)據(jù):

use std::sync::{Arc, Mutex};
use std::thread;fn main() {// 創(chuàng)建一個(gè)Arc包裝的Mutex,以便跨多個(gè)線程安全共享let counter = Arc::new(Mutex::new(0));let mut handles = vec![];// 創(chuàng)建并啟動(dòng)10個(gè)線程for _ in 0..10 {// 克隆Arc來(lái)獲取counter的一個(gè)新引用let counter_clone = Arc::clone(&counter);let handle = thread::spawn(move || {// 通過(guò)lock獲取互斥鎖的訪問(wèn)權(quán)let mut num = counter_clone.lock().unwrap();// 修改數(shù)據(jù)*num += 1;});handles.push(handle);}// 等待所有線程完成for handle in handles {handle.join().unwrap();}// 打印最終的計(jì)數(shù)結(jié)果println!("Result: {}", *counter.lock().unwrap());
}

運(yùn)行結(jié)果

Result: 10

這個(gè)程序執(zhí)行以下步驟:

  1. 使用 Arc::newMutex::new 創(chuàng)建一個(gè)在多個(gè)線程間共享的計(jì)數(shù)器。
  2. 創(chuàng)建一個(gè)線程向量 handles 來(lái)存儲(chǔ)所有線程的句柄。
  3. 在一個(gè)循環(huán)中,為每個(gè)線程克隆 Arc 對(duì)象,以確保每個(gè)線程都有 counter 的獨(dú)立引用。
  4. 每個(gè)線程嘗試獲取 Mutex 的鎖,遞增計(jì)數(shù)器的值,然后釋放鎖。
  5. 使用 thread::spawn 啟動(dòng)每個(gè)線程。
  6. 在主線程中,等待所有子線程完成。
  7. 打印出最終的計(jì)數(shù)結(jié)果。

這個(gè)程序使用了 Arc (Atomic Reference Counting) 來(lái)允許 Mutex 在多個(gè)線程間安全共享。Arc::clone 用于增加內(nèi)部引用計(jì)數(shù),而不是復(fù)制數(shù)據(jù)。每個(gè)線程通過(guò)調(diào)用 lock 方法來(lái)獲取互斥鎖的可變?cè)L問(wèn)權(quán),并通過(guò) unwrap 處理可能的鎖定錯(cuò)誤(在實(shí)際應(yīng)用中,你可能需要更優(yōu)雅地處理這種錯(cuò)誤)。當(dāng) MutexGuard 離開(kāi)作用域時(shí),互斥鎖會(huì)自動(dòng)釋放。

四、使用 Sync 和 Send trait 的可擴(kuò)展并發(fā)

之前討論的幾乎所有內(nèi)容,都屬于標(biāo)準(zhǔn)庫(kù),而不是語(yǔ)言本身的內(nèi)容。由于不需要語(yǔ)言提供并發(fā)相關(guān)的基礎(chǔ)設(shè)施,并發(fā)方案不受標(biāo)準(zhǔn)庫(kù)或語(yǔ)言所限:我們可以編寫(xiě)自己的或使用別人編寫(xiě)的并發(fā)功能。

然而有兩個(gè)并發(fā)概念是內(nèi)嵌于語(yǔ)言中的:std::marker 中的 SyncSend trait。

4.1 通過(guò) Send 允許在線程間轉(zhuǎn)移所有權(quán)

Send 標(biāo)記 trait 表明實(shí)現(xiàn)了 Send 的類型值的所有權(quán)可以在線程間傳送。幾乎所有的 Rust 類型都是 Send 的,不過(guò)有一些例外,包括 Rc<T>:這是不能 Send 的,因?yàn)槿绻寺×?Rc<T> 的值并嘗試將克隆的所有權(quán)轉(zhuǎn)移到另一個(gè)線程,這兩個(gè)線程都可能同時(shí)更新引用計(jì)數(shù)。為此,Rc<T> 被實(shí)現(xiàn)為用于單線程場(chǎng)景,這時(shí)不需要為擁有線程安全的引用計(jì)數(shù)而付出性能代價(jià)。

因此,Rust 類型系統(tǒng)和 trait bound 確保永遠(yuǎn)也不會(huì)意外的將不安全的 Rc<T> 在線程間發(fā)送。而使用標(biāo)記為 SendArc<T> 時(shí),就沒(méi)有問(wèn)題了。

任何完全由 Send 的類型組成的類型也會(huì)自動(dòng)被標(biāo)記為 Send。幾乎所有基本類型都是 Send 的,除了裸指針(raw pointer)。

4.2 Sync 允許多線程訪問(wèn)

Sync 標(biāo)記 trait 表明一個(gè)實(shí)現(xiàn)了 Sync 的類型可以安全的在多個(gè)線程中擁有其值的引用。換一種方式來(lái)說(shuō),對(duì)于任意類型 T,如果 &TT 的不可變引用)是 Send 的話 T 就是 Sync 的,這意味著其引用就可以安全的發(fā)送到另一個(gè)線程。類似于 Send 的情況,基本類型是 Sync 的,完全由 Sync 的類型組成的類型也是 Sync 的。

智能指針 Rc<T> 也不是 Sync 的,出于其不是 Send 相同的原因。RefCell<T>Cell<T> 系列類型不是 Sync 的。RefCell<T> 在運(yùn)行時(shí)所進(jìn)行的借用檢查也不是線程安全的。Mutex<T>Sync 的。

4.3 手動(dòng)實(shí)現(xiàn) Send 和 Sync 是不安全的

通常并不需要手動(dòng)實(shí)現(xiàn) SendSync trait,因?yàn)橛?SendSync 的類型組成的類型,自動(dòng)就是 SendSync 的。因?yàn)樗鼈兪菢?biāo)記 trait,甚至都不需要實(shí)現(xiàn)任何方法。它們只是用來(lái)加強(qiáng)并發(fā)相關(guān)的不可變性的。

手動(dòng)實(shí)現(xiàn)這些標(biāo)記 trait 涉及到編寫(xiě)不安全的 Rust 代碼,當(dāng)前重要的是,在創(chuàng)建新的由不是 SendSync 的部分構(gòu)成的并發(fā)類型時(shí)需要多加小心,以確保維持其安全保證。

以下是一個(gè)完整的示例,展示如何在一個(gè)多線程程序中手動(dòng)實(shí)現(xiàn) SendSync,以及如何在多個(gè)線程之間共享數(shù)據(jù)。

首先,我們定義一個(gè)簡(jiǎn)單的結(jié)構(gòu)體 SharedData,它包含了一些數(shù)據(jù),我們將為這個(gè)結(jié)構(gòu)體手動(dòng)實(shí)現(xiàn) SendSync 特征。

use std::sync::{Arc, Mutex};
use std::thread;// 定義一個(gè)簡(jiǎn)單的結(jié)構(gòu)體,包含一些數(shù)據(jù)
struct SharedData {count: i32,
}// 手動(dòng)實(shí)現(xiàn)Send特征,表示SharedData可以安全地在線程間發(fā)送
unsafe impl Send for SharedData {}// 手動(dòng)實(shí)現(xiàn)Sync特征,表示SharedData可以被多個(gè)線程安全地訪問(wèn)
unsafe impl Sync for SharedData {}fn main() {// 使用Arc來(lái)包裝SharedData,使其可以被多個(gè)線程共享let shared_data = Arc::new(Mutex::new(SharedData { count: 0 }));// 創(chuàng)建多個(gè)線程,它們將共享并修改同一個(gè)SharedData實(shí)例let mut handles = vec![];for i in 0..10 {let data = Arc::clone(&shared_data);let handle = thread::spawn(move || {let mut data = data.lock().unwrap();println!("i: {}", i);data.count += i;});handles.push(handle);}// 等待所有線程完成for handle in handles {handle.join().unwrap();}// 打印最終的count值println!("Final count is: {}", shared_data.lock().unwrap().count);
}

運(yùn)行結(jié)果

i: 1
i: 0
i: 2
i: 9
i: 8
i: 4
i: 3
i: 5
i: 7
i: 6
Final count is: 45

在這個(gè)例子中,我們首先定義了一個(gè) SharedData 結(jié)構(gòu)體,它包含一個(gè) i32 類型的字段 count。然后我們手動(dòng)為 SharedData 實(shí)現(xiàn)了 SendSync 特征,使用 unsafe 關(guān)鍵字,因?yàn)槲覀冃枰_保 SharedData 在多線程環(huán)境中是安全的。

main 函數(shù)中,我們使用 Arc (原子引用計(jì)數(shù)指針)和 Mutex (互斥鎖)來(lái)創(chuàng)建一個(gè)可以在多個(gè)線程之間安全共享的 SharedData 實(shí)例。Arc 允許多個(gè)線程擁有對(duì)數(shù)據(jù)的所有權(quán),而 Mutex 確保在任何時(shí)刻只有一個(gè)線程可以修改數(shù)據(jù)。

我們創(chuàng)建了 10 個(gè)線程,每個(gè)線程都會(huì)增加 SharedData 中的 count 字段的值。由于我們?yōu)?SharedData 實(shí)現(xiàn)了 SendSync,我們可以安全地將 Arc<Mutex<SharedData>> 的克隆傳遞給每個(gè)線程。每個(gè)線程完成其工作后,我們使用 join 方法等待所有線程完成,并打印最終的 count 值。

參考鏈接

  1. Rust 官方網(wǎng)站:https://www.rust-lang.org/zh-CN
  2. Rust 官方文檔:https://doc.rust-lang.org/
  3. Rust Play:https://play.rust-lang.org/
  4. 《Rust 程序設(shè)計(jì)語(yǔ)言》
http://www.risenshineclean.com/news/22291.html

相關(guān)文章:

  • 上海英文網(wǎng)站制作seo怎么發(fā)外鏈的
  • 網(wǎng)站建設(shè)服務(wù)器都有哪些百度網(wǎng)址
  • 懷化網(wǎng)站建設(shè)企業(yè)網(wǎng)絡(luò)軟文推廣案例
  • 蘭州網(wǎng)站做的好點(diǎn)的公司網(wǎng)站制作廠家有哪些
  • 電子商務(wù)網(wǎng)站開(kāi)發(fā)形式有友情鏈接出售網(wǎng)
  • 建設(shè)企業(yè)網(wǎng)站需要哪些東西推廣渠道怎么寫(xiě)
  • wordpress ip更換域名給你一個(gè)網(wǎng)站seo如何做
  • 電子商城開(kāi)發(fā)網(wǎng)站建設(shè)百度一下主頁(yè)官網(wǎng)
  • 電子商務(wù)平臺(tái)知識(shí)產(chǎn)權(quán)保護(hù)管理seo引擎搜索網(wǎng)站關(guān)鍵詞
  • 做寵物網(wǎng)站賺錢(qián)嗎陜西seo主管
  • 企業(yè)網(wǎng)站建設(shè)網(wǎng)站優(yōu)化百度官方認(rèn)證
  • 網(wǎng)易那個(gè)網(wǎng)站可以做字幕外貿(mào)網(wǎng)站建設(shè)設(shè)計(jì)方案
  • 制作一個(gè)app合肥百度搜索排名優(yōu)化
  • 網(wǎng)站優(yōu)化解決方案第一設(shè)計(jì)
  • 雄安網(wǎng)站建設(shè)多少錢(qián)優(yōu)化快速排名公司
  • 公司網(wǎng)站怎么做才能有官網(wǎng)二字新公司如何做推廣
  • 微課做動(dòng)畫(huà)的網(wǎng)站鄭州seo培訓(xùn)
  • 建立個(gè)人網(wǎng)站的方法nba最新交易新聞
  • 鄉(xiāng)鎮(zhèn)中心小學(xué)校園網(wǎng)站建設(shè)指南四川聚順成網(wǎng)絡(luò)科技有限公司
  • 重?c網(wǎng)站開(kāi)發(fā)電腦優(yōu)化是什么意思
  • 合肥室內(nèi)裝修設(shè)計(jì)培訓(xùn)seo排名優(yōu)化北京
  • 網(wǎng)站建設(shè)新手指南百度導(dǎo)航如何設(shè)置公司地址
  • 一品威客網(wǎng)官網(wǎng)靠譜嗎搜索引擎優(yōu)化簡(jiǎn)稱
  • html櫻花飄落代碼seo免費(fèi)工具
  • 好的做淘寶詳情頁(yè)的網(wǎng)站有哪些內(nèi)容貼吧友情鏈接在哪
  • 天津有做網(wǎng)站不錯(cuò)的嗎seo知識(shí)分享
  • 做網(wǎng)站的工資高百度店鋪
  • 兗州建設(shè)公司網(wǎng)站免費(fèi)推廣網(wǎng)站大全
  • 網(wǎng)站美化怎么做站長(zhǎng)工具seo綜合查詢分析
  • 怎樣給網(wǎng)站做外鏈聊城疫情最新消息