创建future
await 关键字用于等待 Future 完成并获取其结果。

async fn async_function() -> i32 {
    42 // 异步返回 42
}

#[tokio::main]
async fn main() {
    let result = async_function().await;
    println!("Result: {}", result);
}

同时等待多个 Future完成

use futures::join;

async fn future_one() -> i32 {
    5
}

async fn future_two() -> String {
    "hello".to_string()
}

#[tokio::main]
async fn main() {
    let (result_one, result_two) = join!(future_one(), future_two());
    println!("Result: {}, {}", result_one, result_two);
}

当一个 Future 完成后执行下一个操作:

use futures::future::FutureExt;

async fn future_one() -> i32 {
    5
}

async fn future_two(v: i32) -> String {
    format!("Value: {}", v)
}

#[tokio::main]
async fn main() {
    let result = future_one()
        .then(|v| future_two(v))
        .await;
    println!("Result: {}", result);
}

捕获错误并处理

use futures::future::TryFutureExt;

async fn future_with_error() -> Result<i32, &str> {
    Err("An error occurred")
}

#[tokio::main]
async fn main() {
    let result = future_with_error().unwrap_or_else(|e| {
        println!("Error: {}", e);
        -1 // 如果发生错误,返回默认值
    }).await;
    println!("Result: {}", result);
}

超时限制

#[tokio::test]
async fn test03() {
    use tokio::time::{timeout, Duration};

    async fn long_running_future() -> i32 {
        tokio::time::sleep(Duration::from_secs(5)).await;
        42
    }

    let result = timeout(Duration::from_secs(2), long_running_future()).await;
    match result {
        Ok(value) => println!("Completed with value: {}", value),
        Err(_) => println!("Timeout occurred"),
    }
}

多个Future的选择和竞赛
有时你希望同时启动多个 Future,并处理第一个完成的那个。

use tokio::time::{sleep, Duration};
use futures::select;
use futures::future::FutureExt;

#[tokio::main]
async fn main() {
    let future1 = sleep(Duration::from_secs(2)).fuse();
    let future2 = sleep(Duration::from_secs(1)).fuse();

    futures::pin_mut!(future1, future2);

    select! {
        _ = future1 => println!("Future1 completed first"),
        _ = future2 => println!("Future2 completed first"),
    }
}

定时任务

#[tokio::test]
async fn test03() {
    use tokio::time::{interval, Duration};

    let mut interval = interval(Duration::from_secs(2)); // 每 2 秒 tick 一次

    for _ in 0..5 {
        interval.tick().await; // 等待下一个 tick
        println!("Tick at {:?}", tokio::time::Instant::now());
    }

    println!("Done");
}

channel //多生产者单消费者通道,用于任务之间的消息传递。

use tokio::sync::mpsc;
use tokio::time::{sleep, Duration};

#[tokio::main]
async fn main() {
    let (tx, mut rx) = mpsc::channel(100);

    // 生产者任务
    for i in 0..5 {
        let tx = tx.clone();
        tokio::spawn(async move {
            tx.send(i).await.unwrap();
            println!("Sent: {}", i);
        });
    }

    // 消费者任务
    tokio::spawn(async move {
        while let Some(value) = rx.recv().await {
            println!("Received: {}", value);
        }
    });

    sleep(Duration::from_secs(1)).await; // 等待所有任务完成
}

设置线程池大小等参数,这个是从同步上下文中启动 Tokio 运行时

use tokio::runtime::Builder;
use std::time::Duration;

fn main() {
    let rt = Builder::new_multi_thread()
        .worker_threads(4)                             // 设置 4 个工作线程
        .max_blocking_threads(32)                      // 设置最大阻塞线程数为 32
        .thread_name("custom-thread")                  // 设置线程名称前缀为 "custom-thread"
        .thread_stack_size(3 * 1024 * 1024)            // 设置每个工作线程的栈大小为 3MB
        .keep_alive(Some(Duration::from_secs(30)))     // 设置线程保持存活时间为 30 秒
        .on_thread_start(|| println!("Thread started"))// 线程启动时打印信息
        .on_thread_stop(|| println!("Thread stopped")) // 线程停止时打印信息
        .enable_all()                                  // 启用所有 Tokio 特性
        .build()
        .unwrap();

    rt.block_on(async {
        // 在自定义运行时中运行异步代码
        println!("Running on custom Tokio runtime");
    });
}


tokio::sync::Mutex 用于在异步环境下保护共享数据,使得同一时间只有一个任务可以访问该数据。

use tokio::sync::Mutex;
use tokio::time::{sleep, Duration};
use std::sync::Arc;

#[tokio::main]
async fn main() {
    let counter = Arc::new(Mutex::new(0)); // 共享计数器

    let mut handles = vec![];

    for _ in 0..5 {
        let counter = Arc::clone(&counter);
        let handle = tokio::spawn(async move {
            for _ in 0..10 {
                let mut num = counter.lock().await;
                *num += 1;
                println!("Incremented to: {}", *num);
                sleep(Duration::from_millis(10)).await; // 模拟异步操作
            }
        });
        handles.push(handle);
    }

    for handle in handles {
        handle.await.unwrap();
    }

    println!("Final counter value: {}", *counter.lock().await);
}

tokio::sync::RwLock 提供了共享锁,允许多个读者并发访问,但同一时间只有一个写者访问。这在读多写少的场景下非常有用。

use tokio::sync::RwLock;
use tokio::time::{sleep, Duration};
use std::sync::Arc;

#[tokio::main]
async fn main() {
    let shared_data = Arc::new(RwLock::new(String::from("initial data"))); // 共享数据

    let mut handles = vec![];

    // 写操作任务
    for i in 0..5 {
        let shared_data = Arc::clone(&shared_data);
        let handle = tokio::spawn(async move {
            let mut data = shared_data.write().await;
            *data = format!("data from task {}", i);
            println!("Write: {}", *data);
            sleep(Duration::from_millis(500)).await; // 模拟异步操作
        });
        handles.push(handle);
    }

    // 读操作任务
    for _ in 0..5 {
        let shared_data = Arc::clone(&shared_data);
        let handle = tokio::spawn(async move {
            loop {
                let data = shared_data.read().await;
                println!("Read: {}", *data);
                sleep(Duration::from_millis(100)).await; // 模拟异步操作
            }
        });
        handles.push(handle);
    }

    // 等待所有任务完成
    futures::future::join_all(handles).await;

    println!("Final shared data: {}", *shared_data.read().await);
}

#[tokio::test]
async fn test04() -> io::Result<()> {
    let mut file = File::create("foo.txt").await?;
    file.write_all(b"Hello, world!").await?;

    let mut file = File::open("foo.txt").await?;
    let mut contents = vec![];
    file.read_to_end(&mut contents).await?;
    println!("File contents: {:?}", String::from_utf8(contents).unwrap());

    Ok(())
}

任务间的同步屏障,等待所有任务到达后继续。

use tokio::sync::Barrier;
use tokio::time::{sleep, Duration};
use std::sync::Arc;

#[tokio::main]
async fn main() {
    let barrier = Arc::new(Barrier::new(3));
    let mut handles = vec![];

    for i in 0..3 {
        let c = barrier.clone();
        let handle = tokio::spawn(async move {
            println!("Task {} is waiting", i);
            c.wait().await;
            println!("Task {} is proceeding", i);
        });
        handles.push(handle);
    }

    for handle in handles {
        handle.await.unwrap();
    }
}

自定义的future
fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output>

  • Pin<&mut Self>:一个被固定的位置指针,表示 Future 自身。通过 Pin 将 &mut Self 转换为 Pin<&mut Self> 来保证其固定位置。
  • Context 提供了对当前异步任务的上下文信息,主要包括唤醒机制。它包含一个 Waker,用于在特定条件满足时唤醒任务继续执行。cx.waker().clone():获取 Waker 的克隆,确保可以在当前作用域外使用它。
impl Future for MyFuture {
    type Output = &'static str;

    fn poll(mut self: Pin<&mut Self>, _cx: &mut Context<'_>) -> Poll<Self::Output> {
        if self.state == 0 {
            self.state += 1;
            println!("Polling MyFuture: Pending");
            Poll::Pending
        } else {
            println!("Polling MyFuture: Ready");
            Poll::Ready("Future is complete")
        }
    }
}

#[tokio::test]
async fn test01() {
    let my_future = MyFuture { state: 0 };

    // println!("Before awaiting MyFuture");
    //
    // // 模拟其他异步操作
    // tokio::spawn(async {
    //     sleep(Duration::from_secs(1)).await;
    //     println!("Simulated async operation completed");
    // });

    let result = my_future.await;

    println!("{}", result);  // 输出: Future is complete
    println!("After awaiting MyFuture");
}


putao
8 声望1 粉丝

推动世界向前发展,改善民生。