Rust tokio使用

一、库引入

为了学习tokio库的全部特性,cargo.toml的配置如下:

tokio = { version = "0.3", features = ["full"] }

二、Task使用示例

1.最简单的示例,验证tokio库导入成功,并能够成功运行。

async fn main() {
    println!("Hello, world!");
}

2.tokio任务阻塞+await示例

use tokio::time::Duration;
 
#[tokio::main] //此处引入tokio 宏/macro
async fn main() {
    //主线程
    tokio::task::spawn_blocking(|| {
        //运行在一个阻塞的线程,可以看作是一个比较耗时的操作
        sleep(Duration::from_millis(10000));
        println!("hi");
    }).await.unwrap();//使用await关键字等待阻塞线程的任务完成
    //要等待阻塞线程完成后,主线程才能执行
    println!("hello");
}

这个示例执行的结果是,等待10s后先输出hi,后输出hello。

3.tokio任务阻塞示例

use tokio::time::Duration;
 
#[tokio::main] //此处引入tokio 宏/macro
async fn main() {
    //主线程
    tokio::task::spawn_blocking(|| {
        //运行在一个阻塞的线程,可以看作是一个比较耗时的操作
        sleep(Duration::from_millis(10000));
        println!("hi");
    });//此处未使用await关键字等待阻塞线程的任务完成
    //无需等待阻塞线程完成,主线程直接执行
    println!("hello");
}

这个示例执行的结果是,先输出hello,然后等待10s输出hi

4.tokio任务不阻塞+await示例

use tokio::time::Duration;
 
#[tokio::main] //此处引入tokio 宏/macro
async fn main() {
    //主线程
    //tokio::task::spawn等价于thread::spawn的异步使用
    tokio::task::spawn(async{
        //运行在一个不阻塞的线程
        sleep(Duration::from_millis(10000));
        println!("hi");
    }).await.unwrap();//使用await关键字等待阻塞线程的任务完成
     //要等待线程完成后,主线程才能执行
    println!("hello");
}

这个示例执行的结果是,等待10s后先输出hi,后输出hello。

5.tokio任务不阻塞示例

use tokio::time::Duration;
 
#[tokio::main] //此处引入tokio 宏/macro
async fn main() {
    //主线程
    //tokio::task::spawn等价于thread::spawn的异步使用
    tokio::task::spawn(async{
        //运行在一个不阻塞的线程
        sleep(Duration::from_millis(10000));
        println!("hi");
    });//此处未使用await关键字等待阻塞线程的任务完成
    //无需等待阻塞线程完成,主线程直接执行
    println!("hello");
}

这个示例执行的结果是,先输出hello,然后等待10s输出hi

6.tokio多任务不阻塞示例

 
#[tokio::main] //此处引入tokio 宏/macro
async fn main() {
    tokio::task::spawn(async {//任务先抢占到线程就先输出hi1,操作耗时多,最后输出
        println!("hi1");
    });
    tokio::task::spawn(async {//任务先抢占到线程就先输出hi2,操作耗时多,最后输出
        println!("hi2");
    });
    println!("hello");
}

这个示例执行的结果是,先输出hello,后输出hi1和hi2,hi1和h2的出现顺序是不确定的。

7.tokio多任务不阻塞+单await示例

async fn main() {
    tokio::task::spawn(async {
        println!("hi1");//一定最先输出
    }).await;
    tokio::task::spawn(async {
        println!("hi2");//任务所属线程可能抢占不到执行所需的资源,主线程直接退出
    });
    println!("hello");//切到主线程,第二输出
}

这个示例执行的结果是,先等待h1输出,而后输出hello,最后输出hi2,也可能不输出hi2.

async fn main() {
    tokio::task::spawn(async {
        println!("hi1");//任务所属线程优先级较高,可以抢占到执行所需的资源
    });
    tokio::task::spawn(async {
        println!("hi2");//一定会执行,使用await会等待任务所属线程先完成,然后执行后续的操作
    }).await;
    println!("hello");//主线程最后执行
}

这个示例执行的结果是,可能先输出hi2,再输出hi1,最后输出hello,也可能是先输出hi1,再输出hi2,最后输出hello(这种可能性高)

8.tokio多任务阻塞示例

async fn main() {
    tokio::task::spawn_blocking(|| {
        //运行在一个阻塞的线程中
        println!("hi1");//分配到专属线程池执行
    });
    tokio::task::spawn_blocking(|| {
        //运行在一个阻塞的线程中
        println!("hi2");//分配到专属线程池执行
    });
    println!("hello");//因为任务处于阻塞,主线程最先输出
}

这个示例执行的结果是,先输出hello,再输出hi1和hi2,h1和h2输出顺序不定,为什么主线程在输出后不直接退出?因为还有任务处于阻塞没有返回,只有阻塞的任务完成,程序才会退出。

9.tokio多任务阻塞+单await示例

async fn main() {
    tokio::task::spawn_blocking(|| {
        println!("hi1");//使用await关键字,主线程需要等待任务执行完成才能执行
    }).await;
    tokio::task::spawn_blocking(|| {
        println!("hi2");//处于阻塞线程,等待主线程执行完,再执行
    });
    println!("hello");
}

这个示例执行的结果是,先输出hi1,然后输出hello,最后输出hi2

async fn main() {
    tokio::task::spawn_blocking(|| {
        println!("hi1");//操作不耗时,直接执行,不能超过await执行的时间,超过最后执行
    });
    tokio::task::spawn_blocking(|| {
        println!("hi2");//使用await关键字,主线程需要等待任务执行完成才能执行
    }).await;
    println!("hello");
}

这个示例执行的结果是,先输出hi1,然后输出hi2,最后输出hello

10.单线程环境下任务阻塞和任务不阻塞示例

use std::thread::sleep;
use tokio::time::Duration;
 
fn main() {
    //构造单线程tokio运行环境
    let runtime = Builder::new_multi_thread().
        max_threads(1).
        enable_all().
        build().
        expect("create tokio runtime failed");
    runtime.spawn(async {//相当于tokio::task::spawn
        //处于单线程中
        println!("hi1");
    });
    runtime.spawn(async {//相当于tokio::task::spawn
        println!("hi2");//处于单线程中
    });
    println!("hello");
}

这个示例执行的结果是,先输出hello,再输出hi1,再输出hi2,这个输出顺序是确定的,和示例6有所区别

use std::thread::sleep;
use tokio::time::Duration;
 
fn main() {
    //构造单线程tokio运行环境
    let runtime = Builder::new_multi_thread().
        max_threads(1).
        enable_all().
        build().
        expect("create tokio runtime failed");
    runtime.spawn(async {//相当于tokio::task::spawn
        //处于单线程中,执行了耗时的操作,影响了其他任务的执行
        sleep(Duration::from_secs(10));
        println!("hi1");
    });
    runtime.spawn(async {//相当于tokio::task::spawn
        println!("hi2");//处于单线程中
    });
    println!("hello");
}

这个示例执行的结果是,先输出hello,等待10s,之后输出hi1,再输出hi2

use std::thread::sleep;
use tokio::time::Duration;
 
fn main() {
    //构造单线程tokio运行环境
    let runtime = Builder::new_multi_thread().
        max_threads(1).
        enable_all().
        build().
        expect("create tokio runtime failed");
    runtime.spawn_blocking(|| {//相当于tokio::task::spawn_blocking
        //处于专属线程池中,执行耗时的操作不影响其他任务执行
        sleep(Duration::from_secs(10));
        println!("hi1");
    });
    runtime.spawn(async {//相当于tokio::task::spawn
        println!("hi2");//处于单线程中
    });
    println!("hello");
}

这个示例执行的结果是,先输出hello,之后输出hi2,等待10s,再输出hi2

总结:可以看出tokio任务阻塞和任务不阻塞的功能大致相同。它们的区别是:tokio::task::spawn开启的任务不应执行可能阻塞的操作,这个任务如果阻塞,这个任务运行时的线程就会被阻塞,在这个线程下的其它任务也会被影响到,直到阻塞消除。tokio::task::spawn_blocking开启的任务可以执行阻塞操作,开启的任务运行在一个专属的线程池中,这个任务如果阻塞,不会影响到其它任务的完成。

11.block_in_place使用示例

async fn main() {
    tokio::task::block_in_place(|| {
        println!("hi1");
    });
    tokio::task::block_in_place(|| {
        println!("hi2");
    });
    println!("hello")
}

这个示例的执行结果是:先输出hi1,再输出hi2,最后输出hello

block_in_place作用和spawn_blocking作用类似,不同之处是,前者阻塞当前线程,等待任务完成后,再将当前线程中的其他任务中转移到另外一个线程执行,后者是将当前任务放到专属的线程池中,线程池选择一个线程阻塞等待任务完成,而当前的线程不会被阻塞。

12.yield_now使用示例

async fn main() {
    tokio::task::spawn(async {//任务时间不能超过await任务的时间,超过最后执行
        println!("hi1");//任务所属线程优先级较高,可以抢占到执行所需的资源
    });
    tokio::task::spawn(async {
        tokio::task::yield_now().await;//此处使用让出时间片,等待其他任务完成
        println!("hi2");//一定会执行,使用await会等待任务所属线程先完成,然后执行后续的操作
    }).await.unwrap();
    println!("hello")
}

这个示例的执行结果:先输出hi1,再输出hi2 ,最后输出hello

————————————————
版权声明:本文为CSDN博主「CrazyWorkers」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/CrazyWorkers/article/details/110877643

  • 3
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值