1. 概述

音讯传递是一种很流行且能确保安全并发的技术,在这种机制里线程(或Actor)经过互相发送音讯(数据)来进行通信。Go言语中有一句名言:“不要用同享内存来通信,要用通信来同享内存”,Go言语这种并发机制就体现了这个思想。

Rust也供给了一种根据音讯传递的并发方式,在rust里运用规范库供给的Channel来完成。Channel包含发送端和接纳端,咱们能够经过调用发送端的办法来发送数据,接纳端会查看和接纳到达的数据。假如发送端和接纳端的任意一端被丢掉了,那么Channel就封闭了。

2. 运用Channel

2.1 在不同线程之间创立和接纳数据

运用mpsc::channel函数来创立Channel,mpsc表明multiple producer, singer consumer(多个生产者、一个顾客),即有多个发送端,但只有一个接纳端。调用该函数将回来一个元组,元组里的元素别离是发送端、接纳端。

如下示例代码:

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 发送端的send办法

该办法的参数为想要发送的数据,回来值为Result<T, E>,假如有问题(例如接纳端已经被丢掉),将回来一个过错。

2.3 接纳端的办法

recv办法阻挠当时线程执行,直到Channel中有值被送来。一旦收到值,就会回来Result<T>,一切这个管道的一切发送端都封闭了,就会收到一个过错。

try_recv办法不会阻塞当时的线程,假如有数据到达,回来OK,里面包含着数据,否则回来过错。咱们通常会运用循环来查看try_recv的成果,假如音讯还没有来,咱们也能够执行其他的操作。

2.4 channel和一切权搬运

一切权先音讯传递中非常重要,能帮你补全编写安全、并发的代码。

咱们先看以下的示例代码:

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

在上面的示例代码中,借用了已移动的值,因此会产生编译过错。所以一切权机制会帮助咱们编写编写安全、并发的代码。

2.5 发送多个值

咱们经过发送多个值,就能够看到接纳者在等待的进程。

如下示例代码:

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"),
        ];
        // 循环别离发送四个字符
        for val in vals {
            tx.send(val).unwrap();
            thread::sleep(Duration::from_millis(1000));
        }
    });
    // 咱们把接纳端当作迭代器来运用,这样就不需求显式调用recv办法
    for received in rx {
        println!("Got: {}", received);
    }
}

运转以上的代码,咱们将看到接纳端在等待音讯的进程。

2.6 经过克隆创立多个发送者

经过调用mpsc::Sender::clone函数能够克隆发送者。

如下示例代码:

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"),
        ];
        // 循环别离发送四个字符串
        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"),
        ];
        // 循环别离发送四个字符串
        for val in vals {
            tx.send(val).unwrap();
            thread::sleep(Duration::from_millis(200));
        }
    });
    // 咱们把接纳端当作迭代器来运用,这样就不需求显式调用recv办法
    for received in rx {
        println!("Got: {}", received);
    }
}

在以上的示例代码中,咱们经过两个子线程由两个发送者来发数据。并在主线程中运用接纳者接纳数据,能够经进程序运转成果看到由两个发送者发送的数据被交替输出。