Rust真tema难啊...
任务
Tokio任务是一个异步绿色线程,它们通过向tokio::spawn
中传递一个async
块来创建。tokio::spawn
函数返回一个JoinHandle
,调用者可能使用它来与被创建的任务交互。async
块可能有一个返回值,调用者可以通过在JoinHandle
上.await
来获取这个返回值。
#[tokio::main]
async fn main() {
let handle = tokio::spawn(async {
// Do some async work
"return value"
});
// Do some other work
let out = handle.await.unwrap();
println!("GOT {}", out);
}
JoinHandle
返回一个Result
,当任务遇到一个错误,JoinHandle
将返回一个Err
,这会发生在任务panic或者由于运行时关闭而被强制取消。
任务是被调度器所管理的执行单元,产生(spawning)任务就是向tokio的调度器提交它,也就是确保任务会在它有事要做时得到执行。产生的任务可能会在它产生时相同的线程执行,或者可能在一个不同的运行时线程执行,任务也可以在产生后在线程间移动。
'static
bound
当你向tokio运行时产生一个task时,它的生命周期必须是'static
的,这意味着被生成的task必须不能包含任何被任务外部所拥有的数据的引用。
比如,下面的代码是无法编译的
use tokio::task;
#[tokio::main]
async fn main() {
let v = vec![1, 2, 3];
task::spawn(async {
println!("Here's a vec: {:?}", v);
});
}
这是很重要的,因为编译器并不知道一个新产生的任务会驻留多久,所以我们必须让确保让任务能够永远运行下去。
Send
bound
被tokio::spawn
调用产生的Task必须实现了Send
,这允许Tokio运行时在Task在.await
上挂起时在线程间移动它们。
当Task中所有的被await
调用所保持住的数据是Send
的,Task就是Send的。这可能并不容易察觉。当.await
被调用了,任务就会返回(yield)给调度程序,当下次任务被执行时,它从上一次返回的点恢复。为了使这成为可能,所有在.await
之后要用到的状态都必须被任务保存。如果状态是Send
,任务本身就是Send
,反之亦然。
比如,下面的代码可以工作:
use tokio::task::yield_now;
use std::rc::Rc;
#[tokio::main]
async fn main() {
tokio::spawn(async {
// scope迫使`rc`在`.await`前drop
{
let rc = Rc::new("hello");
println!("{}", rc);
}
// `rc`不会再被用到,当任务返回到调度器时,它不会被持久化
yield_now().await;
});
}
下面的不行:
use tokio::task::yield_now;
use std::rc::Rc;
#[tokio::main]
async fn main() {
tokio::spawn(async {
let rc = Rc::new("hello");
// `rc`在`.await`之后也会用到,他必须被持久化到任务状态中
yield_now().await;
println!("{}", rc);
});
}
共享状态 策略
在Tokio中有一些共享状态的策略
- 使用Mutex来保护共享状态
- 使用一个任务来管理状态,并且使用消息来向它传递操作
任务,线程以及争用
使用一个阻塞互斥量(Mutex)来保护较短的关键部分是一个在争用较小情况下可接受的策略。当锁被征用,执行任务的线程必须阻塞并等待锁,这不仅会阻塞当前任务,也会阻塞所有在当前线程上被调度的其它任务。
默认情况下,Tokio运行时使用多线程调度器,任务会在任意数量的被运行时管控的线程内执行,如果很大数量的任务被调度执行,并且它们都需要获取互斥量,就将会出现争用。另一方面,如果current_thread
运行时flavor被使用了,互斥量将永远不会被争用。
current_thread
运行时flavor是一个轻量级,单线程的运行时flavor,当你只会产生少量的任务并且只打开少数Socket时,它是一个不错的选择。当你想在一个异步客户端库上提供一个同步的API bridge时,这是一个很好的选择。
如果同步互斥量的争用成为一个问题时,最好的选择几乎很少是切换到Tokio的mutex上,相反,你可以考虑如下选择:
- 切换到专用的管理状态的任务,以及使用消息传递
- 对mutex进行分片
- 重构代码以避免mutex
标签:await,rc,任务,官方,文档,tokio,async,main From: https://www.cnblogs.com/lilpig/p/16999327.html官方文档中编写了一个分片的小示例,非常有意思,由于本篇不想卷入代码,所以有兴趣请参考官方文档