Skip to content

Rust 异步编程

异步编程是 Rust 中处理并发的一种方式,它允许我们在等待 I/O 操作时执行其他任务。本章节将介绍 Rust 中的异步编程。

异步编程基础

异步函数

使用 async 关键字定义异步函数:

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

fn main() {
    let future = hello();
    // 执行 future
    tokio::runtime::Runtime::new().unwrap().block_on(future);
}

Future

异步函数返回一个 Future,它表示一个异步操作:

rust
use std::future::Future;

async fn add(a: i32, b: i32) -> i32 {
    a + b
}

fn main() {
    let future: impl Future<Output = i32> = add(5, 3);
    let result = tokio::runtime::Runtime::new().unwrap().block_on(future);
    println!("Result: {}", result);
}

异步运行时

Tokio

Tokio 是 Rust 中最流行的异步运行时:

rust
use tokio::time::{sleep, Duration};

async fn say_hello() {
    println!("Hello");
    sleep(Duration::from_secs(1)).await;
    println!("World");
}

#[tokio::main]
async fn main() {
    say_hello().await;
}

async-std

async-std 是另一个流行的异步运行时:

rust
use async_std::task::sleep;
use std::time::Duration;

async fn say_hello() {
    println!("Hello");
    sleep(Duration::from_secs(1)).await;
    println!("World");
}

#[async_std::main]
async fn main() {
    say_hello().await;
}

await 关键字

使用 await 关键字等待异步操作完成:

rust
use tokio::time::{sleep, Duration};

async fn task1() {
    println!("Task 1 started");
    sleep(Duration::from_secs(1)).await;
    println!("Task 1 completed");
}

async fn task2() {
    println!("Task 2 started");
    sleep(Duration::from_secs(2)).await;
    println!("Task 2 completed");
}

#[tokio::main]
async fn main() {
    // 串行执行
    task1().await;
    task2().await;
    
    // 并行执行
    let t1 = tokio::spawn(task1());
    let t2 = tokio::spawn(task2());
    t1.await.unwrap();
    t2.await.unwrap();
}

异步 I/O

异步文件操作

rust
use tokio::fs::File;
use tokio::io::{self, AsyncReadExt, AsyncWriteExt};

#[tokio::main]
async fn main() -> io::Result<()> {
    // 写入文件
    let mut file = File::create("hello.txt").await?;
    file.write_all(b"Hello, async I/O!").await?;
    
    // 读取文件
    let mut file = File::open("hello.txt").await?;
    let mut contents = String::new();
    file.read_to_string(&mut contents).await?;
    println!("File contents: {}", contents);
    
    Ok(())
}

异步网络操作

rust
use tokio::net::TcpListener;
use tokio::io::{self, AsyncReadExt, AsyncWriteExt};

#[tokio::main]
async fn main() -> io::Result<()> {
    let listener = TcpListener::bind("127.0.0.1:8080").await?;
    println!("Server listening on 127.0.0.1:8080");
    
    loop {
        let (mut socket, _) = listener.accept().await?;
        
        tokio::spawn(async move {
            let mut buffer = [0; 1024];
            
            // 读取数据
            let n = socket.read(&mut buffer).await.unwrap();
            println!("Received: {}", String::from_utf8_lossy(&buffer[..n]));
            
            // 发送数据
            socket.write_all(b"Hello from server!").await.unwrap();
        });
    }
}

异步流

Stream

Stream 是异步的迭代器:

rust
use tokio::stream::StreamExt;
use tokio::time::{interval, Duration};

#[tokio::main]
async fn main() {
    let mut interval = interval(Duration::from_millis(100));
    
    let mut count = 0;
    while let Some(_) = interval.next().await {
        println!("Tick {}", count);
        count += 1;
        if count >= 5 {
            break;
        }
    }
}

错误处理

Result 和 async

rust
use tokio::fs::File;
use tokio::io::{self, AsyncReadExt};

async fn read_file() -> Result<String, io::Error> {
    let mut file = File::open("hello.txt").await?;
    let mut contents = String::new();
    file.read_to_string(&mut contents).await?;
    Ok(contents)
}

#[tokio::main]
async fn main() {
    match read_file().await {
        Ok(contents) => println!("File contents: {}", contents),
        Err(e) => println!("Error: {}", e),
    }
}

总结

  • 异步函数:使用 async 关键字定义
  • Future:表示一个异步操作
  • 异步运行时:Tokio 和 async-std
  • await:等待异步操作完成
  • 异步 I/O:文件和网络操作
  • Stream:异步迭代器
  • 错误处理:与同步代码类似

异步编程是 Rust 中处理并发的强大工具,它允许我们在等待 I/O 操作时执行其他任务,从而提高程序的效率。通过本章节的学习,你应该已经掌握了 Rust 中异步编程的基本概念和使用方法。