Rust使用Channel實現跨線程傳遞數據
1. 概述
消息傳遞是一種很流行且能保證安全并發(fā)的技術,在這種機制里線程(或Actor)通過彼此發(fā)送消息(數據)來進行通信。Go語言中有一句名言:“不要用共享內存來通信,要用通信來共享內存”,Go語言這種并發(fā)機制就體現了這個思想。
Rust也提供了一種基于消息傳遞的并發(fā)方式,在rust里使用標準庫提供的Channel來實現。Channel包含發(fā)送端和接收端,我們可以通過調用發(fā)送端的方法來發(fā)送數據,接收端會檢查和接收到達的數據。如果發(fā)送端和接收端的任意一端被丟棄了,那么Channel就關閉了。
2. 使用Channel
2.1 在不同線程之間創(chuàng)建和接收數據
使用mpsc::channel函數來創(chuàng)建Channel,mpsc表示multiple producer, singer consumer(多個生產者、一個消費者),即有多個發(fā)送端,但只有一個接收端。調用該函數將返回一個元組,元組里的元素分別是發(fā)送端、接收端。
如下示例代碼:
use std::sync::mpsc;
use std::thread;
fn main() {
let (tx, rx) = mpsc::channel();
thread::spawn(move || {
let val = String::from("hi");
tx.send(val).unwrap();
});
let received = rx.recv().unwrap();
println!("Got: {}", received);
}
消費者的recv方法一直會阻塞當前線程,直到接收到消息為止。
2.2 發(fā)送端的send方法
該方法的參數為想要發(fā)送的數據,返回值為Result<T, E>,如果有問題(例如接收端已經被丟棄),將返回一個錯誤。
2.3 接收端的方法
recv方法阻止當前線程執(zhí)行,直到Channel中有值被送來。一旦收到值,就會返回Result<T>,所有這個管道的所有發(fā)送端都關閉了,就會收到一個錯誤。
try_recv方法不會阻塞當前的線程,如果有數據到達,返回OK,里面包含著數據,否則返回錯誤。我們通常會使用循環(huán)來檢查try_recv的結果,如果消息還沒有來,我們也可以執(zhí)行其他的操作。
2.4 channel和所有權轉移
所有權先消息傳遞中非常重要,能幫你補全編寫安全、并發(fā)的代碼。
我們先看以下的示例代碼:
use std::sync::mpsc;
use std::thread;
fn main() {
let (tx, rx) = mpsc::channel();
thread::spawn(move || {
let val = String::from("hi");
tx.send(val).unwrap();
// 下面一行代碼將會報錯,因為所有權已經被轉移
println("val is {}", val);
});
let received = rx.recv().unwrap();
println!("Got: {}", received);
}
在上面的示例代碼中,借用了已移動的值,因此會發(fā)生編譯錯誤。所以所有權機制會幫助我們編寫編寫安全、并發(fā)的代碼。
2.5 發(fā)送多個值
我們通過發(fā)送多個值,就可以看到接收者在等待的過程。
如下示例代碼:
use std::sync::mpsc;
use std::{thread, vec};
use std::time::Duration;
fn main() {
let (tx, rx) = mpsc::channel();
thread::spawn(move || {
let vals = vec![
String::from("hi"),
String::from("from"),
String::from("the"),
String::from("thread"),
];
// 循環(huán)分別發(fā)送四個字符串
for val in vals {
tx.send(val).unwrap();
thread::sleep(Duration::from_millis(1000));
}
});
// 我們把接收端當作迭代器來使用,這樣就不需要顯式調用recv方法
for received in rx {
println!("Got: {}", received);
}
}
運行以上的代碼,我們將看到接收端在等待消息的過程。
2.6 通過克隆創(chuàng)建多個發(fā)送者
通過調用mpsc::Sender::clone函數可以克隆發(fā)送者。
如下示例代碼:
use std::sync::mpsc;
use std::{thread, vec};
use std::time::Duration;
fn main() {
let (tx, rx) = mpsc::channel();
let tx1 = mpsc::Sender::clone(&tx);
thread::spawn(move || {
let vals = vec![
String::from("1: hi"),
String::from("1: from"),
String::from("1: the"),
String::from("1: thread"),
];
// 循環(huán)分別發(fā)送四個字符串
for val in vals {
tx1.send(val).unwrap();
thread::sleep(Duration::from_millis(200));
}
});
thread::spawn(move || {
let vals = vec![
String::from("hi"),
String::from("from"),
String::from("the"),
String::from("thread"),
];
// 循環(huán)分別發(fā)送四個字符串
for val in vals {
tx.send(val).unwrap();
thread::sleep(Duration::from_millis(200));
}
});
// 我們把接收端當作迭代器來使用,這樣就不需要顯式調用recv方法
for received in rx {
println!("Got: {}", received);
}
}
在以上的示例代碼中,我們通過兩個子線程由兩個發(fā)送者來發(fā)數據。并在主線程中使用接收者接收數據,可以通過程序運行結果看到由兩個發(fā)送者發(fā)送的數據被交替輸出。
到此這篇關于Rust使用Channel實現跨線程傳遞數據的文章就介紹到這了,更多相關Rust Channel跨線程傳遞數據內容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!

