Skip to content

Rust Async

· 3 min

异步介绍

异步#

异步库:tokio, soml

资料

https://www.modb.pro/db/248295

https://www.freesion.com/article/5043318152/

Send 和 Sync#

Send:变量可以安全的发送给另一个线程, Sync:可以在多个线程之前共享,(当且仅当 &T 实现了 Send 时,T 实现了 Send)

https://www.yisu.com/zixun/542835.html

Future#

pub trait Future {
type Output;
fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output>;
}
pub enum Poll<T> {
Ready(T),
Pending,
}

开始时,先执行一遍 poll,返回 Poll.Pending 时,执行器不会轮询 poll 来查询状态,而是 poll 函数内部通过 cx.waker().wake() 通知执行器执行一遍 poll。

资料

https://zhuanlan.zhihu.com/p/161971936

零成本异步 I/O - 不明觉疼的文章 - 知乎

Channels#

通道原语:

mpsc:多生产者、单消费者 oneshot:单生产者、单消费者 broadcast:多生产者、多消费者 watch:单生产者、多消费者,send 多个,接收一个

在多线程执行者上进行 .await#

future 可以在线程间移动,这意味着

  1. 不可以使用 Rc,&RefCell
  2. 不可以使用任何其他没有实现 Send trait 类型 和 没有实现 Sync trait 的引用
  3. 使用库提供的锁,不可以使用 std::sync 里的 Mutex,

Tokio#

  1. 总览 https://zhuanlan.zhihu.com/p/460984955
  2. 初印象 https://zhuanlan.zhihu.com/p/461044853
  3. 创建异步任务 https://zhuanlan.zhihu.com/p/461384827
  4. 共享状态 https://zhuanlan.zhihu.com/p/461874095
  5. 消息传递 https://zhuanlan.zhihu.com/p/462116823

Rust 异步开发#

深入了解 Rust 异步开发模式

Zero-cost futures in Rust

0000-remove-runtime

Abandoning segmented stacks in Rust

线程方法#

join

use std::thread;
use std::time::Duration;
fn main() {
let new_thread = thread::spawn(move || {
});
// 阻塞,等待线程执行完成
new_thread.join().unwrap();
}

线程屏障(Barrier)

在 Rust 中,可以使用 Barrier 让多个线程都执行到某个点后,才继续一起往后执行

以下代码打印 6 条 before wait 后,才打印 6 条 after wait。不会出现 before wait 和 after wait 交替打印

use std::sync::{Arc, Barrier};
use std::thread;
fn main() {
let mut handles = Vec::with_capacity(6);
let barrier = Arc::new(Barrier::new(6));
for _ in 0..6 {
let b = barrier.clone();
handles.push(thread::spawn(move|| {
println!("before wait");
b.wait();
println!("after wait");
}));
}
for handle in handles {
handle.join().unwrap();
}
}

线程间的消息传递#

mpsc:多发送者,单接收者

use std::sync::mpsc;
use std::thread;
fn main() {
// 创建一个消息通道, 返回一个元组:(发送者,接收者)
let (tx, rx) = mpsc::channel();
// 创建线程,并发送消息
thread::spawn(move || {
// 发送一个数字1, send方法返回Result<T,E>,通过unwrap进行快速错误处理
tx.send(1).unwrap();
});
// 阻塞,在主线程中接收子线程发送的消息并输出
println!("receive {}", rx.recv().unwrap());
// 不阻塞,没有消息报错
// println!("receive {:?}", rx.try_recv());
}

使用通道来 send() 数据,一样要遵循 Rust 的所有权规则:

  1. 若值的类型实现了 Copy 特征,则直接复制一份该值,然后传输过去
  2. 若值没有实现 Copy,则它的所有权会被转移给接收端,在发送端继续使用该值将报错