Rust:并发编程(concurrent programming)

得益于所有权系统以及类型系统,Rust有着非常优异的并发性能。

1. 线程的基本应用

创建线程:

use std::thread;
use std::time::Duration;
fn main() {
     thread::spawn(|| {
         for i in 1..10 {
         println!("hi number {} from the spawned thread!", i);
         thread::sleep(Duration::from_millis(1));
         }
 });

 for i in 1..5 {
     println!("hi number {} from the main thread!", i);
     thread::sleep(Duration::from_millis(1));
     }
}
hi number 1 from the main thread!
hi number 1 from the spawned thread!
hi number 2 from the spawned thread!
hi number 2 from the main thread!
hi number 3 from the main thread!
hi number 3 from the spawned thread!
hi number 4 from the spawned thread!
hi number 4 from the main thread!
hi number 5 from the spawned thread!

需要注意的是,当主线程结束,不管thread::spawn创建的子线程是否执行完毕,程序都会结束。所以子线程的print语句只执行到了i=5。

使用Join()让主线程等待子线程执行完毕:

如果我们想让子线程执行完毕,可以将thread::spawn赋给变量,然后调用join。在rust中,thread::spawn返回的type是JoinHandle。

use std::thread;
use std::time::Duration;
fn main() {
    //thread::spawn创建线程后返回JoinHandle 类型给handle
     let handle = thread::spawn(|| {
     for i in 1..10 {
         println!("hi number {} from the spawned thread!", i);
         thread::sleep(Duration::from_millis(1));
         }
     });
     for i in 1..5 {
         println!("hi number {} from the main thread!", i);
         thread::sleep(Duration::from_millis(1));
         }
    //调用join,让主线程等待至子线程执行完毕
    //unwrap的作用:请求返回结果,如果报错就会panic并停止程序
     handle.join().unwrap();
}
hi number 1 from the main thread!
hi number 2 from the main thread!
hi number 1 from the spawned thread!
hi number 3 from the main thread!
hi number 2 from the spawned thread!
hi number 4 from the main thread!
hi number 3 from the spawned thread!
hi number 4 from the spawned thread!
hi number 5 from the spawned thread!
hi number 6 from the spawned thread!
hi number 7 from the spawned thread!
hi number 8 from the spawned thread!
hi number 9 from the spawned thread!

使用Move让线程获得变量所有权

在Rust里,当闭包函数使用外界环境的变量时,编译器会推断闭包函数该采用借用,还是获取变量所有权的方式。当创建的子线程需要使用主线程的数据时,由于闭包函数运行子线程环境中而无法确定借用是否一直有效,所以需要使用move来使变量所有权移交至子线程的闭包函数。

use std::thread;
fn main() {
     let v = vec![1, 2, 3];
    //使用move移交所有权至子线程
     let handle = thread::spawn(move|| {
         println!("Here's a vector: {:?}", v);
         });
 handle.join().unwrap();
}

2. 线程通信机制:channel,transmitter与receiver

Rust book中将rust的线程通信的channel比作一条河,数据比作橡皮鸭。橡皮鸭从上游(transmitter)顺流而下到下游(receiver)。Rust中实现线程通信的标准库为mpsc,是multiple producer; single consumer的缩写。意思是在rust线程通信机制中,可以有多个数据发送端,然后像河流汇聚到大海一般,最终由一个接受端接收。

use std::thread;
use std::sync::mpsc;
fn main() {
   //创建channel
  //mpsc::channel()返回一个tuple,包含transmitter:tx , receiver:rx
  //在很多领域tx,rx都被当做是transmitter与receiver的缩写
  //所以rust book的这个例子也以此来命名
   let (tx, rx) = mpsc::channel();

   thread::spawn(move || {
       let val = String::from("hi");
       //transmitter从子线程发送数据
       tx.send(val).unwrap();
       //需要注意的是,此时val的所有权也被移交给了数据的接收线程
 });

   //主线程接受子线程数据
   let received = rx.recv().unwrap();
   println!("Got: {}", received);
}
Got: hi

Sending Multiple Values and Seeing the Receiver Waiting:

为了直观展现出两个线程通过channel保持communicating,对上述代码做出一点修改:使用for循环发送多条value,并且每次发送间隔1秒。同样也以for循环在主线程中接收数据,这时rx被当作一个iterator。每当接收到一条数据,for循环就会执行一次。直到数据发送完毕,channel关闭。

use std::thread;
use std::sync::mpsc;
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_secs(1));
             }
      });

     for received in rx {
         println!("Got: {}", received);
     }
}

应该可以直观的看到每条数据之间都间隔了1秒。

Got: hi
Got: from
Got: the
Got: thread

使用clone函数实现mpsc: multiple producer; single consumer

use std::thread;
use std::sync::mpsc;
use std::time::Duration;
fn main() {
     let (tx, rx) = mpsc::channel();
     //使用clone函数clone一个transmitter
     let tx1 = mpsc::Sender::clone(&tx);

     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_secs(1));
           }
     });
     thread::spawn(move || {
         let vals = vec![
           String::from("more"),
           String::from("messages"),
           String::from("for"),
           String::from("you"),
           ];
         for val in vals {
           tx1.send(val).unwrap();
           thread::sleep(Duration::from_secs(1));
           }
     });
     for received in rx {
         println!("Got: {}", received);
 }
}
Got: hi
Got: more
Got: from
Got: messages
Got: the
Got: for
Got: you
Got: thread

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值