首页 > 其他分享 >tokio官方文档中一些值得记录的

tokio官方文档中一些值得记录的

时间:2022-12-22 18:13:17浏览次数:57  
标签:await rc 任务 官方 文档 tokio async main

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中有一些共享状态的策略

  1. 使用Mutex来保护共享状态
  2. 使用一个任务来管理状态,并且使用消息来向它传递操作

任务,线程以及争用

使用一个阻塞互斥量(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

相关文章