tokio::runtime详解

  1. 简介
    tokio是rust的io事件驱动库,本文主要介绍了tokio的runtime,内容来自官方文档,对应tokio版本v1.38.0

  2. 异步应用程序需要的运行时支持
    I/O事件循环。
    执行使用I/O资源的任务调度程序。
    定时器

  3. .运行时的使用
    使用宏的方式

    use tokio::net::TcpListener;
    use tokio::io::{AsyncReadExt, AsyncWriteExt};
    #[tokio::main]
    async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let listener = TcpListener::bind("127.0.0.1:8080").await?;
    
    loop {
        let (mut socket, _) = listener.accept().await?;
    
        tokio::spawn(async move {
            let mut buf = [0; 1024];
    
            // In a loop, read data from the socket and write the data back.
            loop {
                let n = match socket.read(&mut buf).await {
                    // socket closed
                    Ok(n) if n == 0 => return,
                    Ok(n) => n,
                    Err(e) => {
                        println!("failed to read from socket; err = {:?}", e);
                        return;
                    }
                };
    
                // Write the data back
                if let Err(e) = socket.write_all(&buf[0..n]).await {
                    println!("failed to write to socket; err = {:?}", e);
                    return;
                }
            }
        });
    }
    

}
```
使用手动设置

use tokio::net::TcpListener;
use tokio::io::{AsyncReadExt, AsyncWriteExt};
use tokio::runtime::Runtime;

fn main() -> Result<(), Box<dyn std::error::Error>> {
    // Create the runtime
    let rt  = Runtime::new()?;

    // Spawn the root task
    rt.block_on(async {
        let listener = TcpListener::bind("127.0.0.1:8080").await?;

        loop {
            let (mut socket, _) = listener.accept().await?;

            tokio::spawn(async move {
                let mut buf = [0; 1024];

                // In a loop, read data from the socket and write the data back.
                loop {
                    let n = match socket.read(&mut buf).await {
                        // socket closed
                        Ok(n) if n == 0 => return,
                        Ok(n) => n,
                        Err(e) => {
                            println!("failed to read from socket; err = {:?}", e);
                            return;
                        }
                    };

                    // Write the data back
                    if let Err(e) = socket.write_all(&buf[0..n]).await {
                        println!("failed to write to socket; err = {:?}", e);
                        return;
                    }
                }
            });
        }
    })
}
  1. 运行时的配置
    5.1 调度器选择
    多线程调度
    需要rt-multi-thread特性支持,使用了线程池,线程之间使用的任务调度策略使用的是work-stealing(当前线程任务队列是空的时,可以从其他线程取任务,以便把任务在各个线程上均匀分布),默认情况下在每个cpu核心上启动一个工作线程,大部分应用使用此调度策略。

    当前线程调度
    单线程调度,所有任务在一个线程上执行。
    5.2 资源驱动
    当使用手动设置运行时的情况下,默认i/o和定时器无法使用,需要设置Builder::enable_io and Builder::enable_time分别开启相应资源,可以使用Builder::enable_all同时开启两个。
    5.3 线程的生命周期
    当运行时正常时,线程执行结束会可以结束。
    当运行时异常结束时,线程都会停止。
    5.4 详细运行时行为
    当任务调度时,tokio为防止个别任务频率过高而调度不到其他任务做了个策略,使用三个变量
    MAX_TASKS,MAX_SCHEDULE,MAX_DELAY。
    5.5 I/O和定时器
    除了调度任务,还需要检查i/o和定时器事件是否准备就绪,如果就绪就唤醒相应任务准备调度
    单线程
    维护了两个队列,一个全局的,一个本地的,调度的时候优先从本地队列中获取任务,当本地任务是空的,或者从本地连续获取了31次任务进行调度,那么就会从全局队列获取,31可配置
    当没有任务被调度,或者连续调度了61个任务,那么将检查i/o和定时器是否有任务就绪,61可配置。如果正在执行的任务唤醒了另一个任务,此任务直接加入本地队列,否则加入全局队列。
    多线程
    拥有固定个数的工作线程,和一个全局的队列,每个工作线程拥有一个本地队列,本地队列最多有256个任务,如果超过直接把一半任务移动到全局队列。
    优先选择从本地队列获取任务进行调度,如果本地队列是空的,或者工作线程连续从本地队列调度了global_queue_interval次任务,那么会从全局队列获取任务进行调度,如果global_queue_interval没有被显示的设置,那么由tokio进行动态推断global_queue_interval的值。
    如果全局队列和本地队列都是空的,就会从其他工作线程的本地队列获取,每次获取对方的一半数量的任务,
    工作线程没有任务调度,或者连续调度任务61(可设置)次会检查i/o和定时器是否有任务就绪。
    多线程使用了lifo槽优化,如果一个任务唤醒了另一个任务,此时唤醒的任务加入lifo槽中,当槽中已经有任务了,会直接把槽中的任务放到本地队列,此任务然后再放入槽中。当运行中的任务结束之后会立即执行Lifo槽中的任务,如果调度的任务连续来自槽中,tokio会临时禁止调度槽中任务,直到有一个调度的任务不是来自槽中,由于槽中数据和本地线程是分离的,其他线程无法获取本线程槽中的任务。如果一个任务不是工作线程获取的,它会被放入到全局队列。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值