Learn Rust Coding · 课时

使用 Tokio 构建异步应用

使用 Tokio 运行时高效执行异步任务,处理 I/O 和其他并发操作。

第 2 / 3 课11 个步骤

使用 Tokio 构建异步应用 是 CoddyKit 上的免费 Learn Rust Coding 课时。 这是第 2 节课,共 3 节。 你可以在下方免费阅读本课时的完整内容 — 然后在浏览器中使用内置代码编辑器和全天候 AI 导师进行实践。 这是 Learn Rust Coding 学习路径的一部分,你的进度在网页和 CoddyKit 应用中同步。 Learn Rust Coding 课程共包含 3 节课。

认识 Tokio 运行时

欢迎回来!在上一课中,您学习了async和await。但是,async函数究竟是如何运行的呢?

这正是 Tokio 这样的异步运行时发挥作用的地方。Tokio 是一个功能强大的库,为您的异步 Rust 代码提供执行环境。

  • 它会调度并执行Future。
  • 处理非阻塞 I/O 操作。
  • 高效地管理并发任务。

运行您的异步代码

要开始使用 Tokio,通常需要使用#[tokio::main]属性宏。这个宏会将您的async fn main()转换为标准的fn main(),后者会初始化 Tokio 运行时并运行您的异步代码。

您可以把它看作异步应用的入口点。

use tokio;

#[tokio::main]
async fn main() {
  println!("Hello from Tokio!");
}

生成新的异步任务

Tokio 的核心功能之一,是能够并发运行多个异步操作。您可以使用tokio::spawn来实现这一点。

tokio::spawn接收一个Future,并将其调度到 Tokio 运行时上运行。这样,主任务可以继续执行,同时生成的任务会在后台运行。

  • 它不会阻塞。
  • 它会返回一个JoinHandle,用于等待任务完成。
  • 各个任务彼此独立地运行。

<code>tokio::spawn</code>实战

让我们看看tokio::spawn如何让您并发执行代码。请注意,两条消息都会出现,但由于休眠操作,"done"消息可能会先于"task complete"消息打印出来。

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

#[tokio::main]
async fn main() {
  // Spawn a new task
  let handle = tokio::spawn(async {
    sleep(Duration::from_secs(1)).await;
    println!("Async task complete!");
  });

  println!("Main task continuing...");

  // Wait for the spawned task to finish
  handle.await.unwrap();
  println!("All tasks done.");
}

等待多个任务

当您有多个任务时,通常需要等待它们全部完成。Tokio 提供了tokio::join!宏来实现这一目的。

tokio::join!允许您并发等待多个 future,并组合它们的结果。它类似于等待多个JoinHandle,但对于固定的一组 future,通常写法更简洁。

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

#[tokio::main]
async fn main() {
  let task1 = async {
    sleep(Duration::from_secs(1)).await;
    println!("Task 1 finished");
    1
  };

  let task2 = async {
    sleep(Duration::from_millis(500)).await;
    println!("Task 2 finished");
    2
  };

  let (result1, result2) = tokio::join!(task1, task2);
  println!("Results: {}, {}", result1, result2);
}

使用 Tokio 进行异步文件 I/O

传统的文件操作可能会阻塞线程,这对异步应用来说是不利的。Tokio 的tokio::fs模块提供了文件系统操作的异步版本。

这样一来,即使读取大型文件或执行许多文件操作,您的应用也能保持响应,因为 I/O 会以非阻塞方式处理。

  • tokio::fs::read_to_string
  • tokio::fs::write
  • 需要更多控制时使用tokio::fs::File

异步读取文件

下面介绍如何使用tokio::fs::read_to_string异步读取文件。要运行这段代码,请确保 Rust 项目的同一目录中有一个名为hello.txt的文件(例如位于src/目录中或项目根目录下),并且文件中包含一些内容。

use tokio::fs;

#[tokio::main]
async fn main() {
  let path = "hello.txt";
  // Create a dummy file for the example if it doesn't exist
  // In a real app, you'd handle file creation/existence more robustly
  if let Err(_) = fs::metadata(path).await {
    fs::write(path, "Hello, Tokio file!").await.unwrap();
  }

  match fs::read_to_string(path).await {
    Ok(content) => println!("File content: '{}'", content),
    Err(e) => eprintln!("Error reading file: {}", e),
  }
}

异步网络操作

Tokio 在网络编程中真正展现了实力。它的tokio::net模块为 TCP 和 UDP 通信提供了非阻塞基础功能。

这对于构建高性能服务器或客户端至关重要,因为它们可以同时处理许多连接,而不必为每个连接创建单独的线程。

  • 服务器使用tokio::net::TcpListener。
  • 客户端连接使用tokio::net::TcpStream。

异步 TCP 服务器的基本结构

虽然完整的服务器较为复杂,但这段代码展示了使用 Tokio 构建的异步 TCP 服务器的核心循环。它会监听传入的连接,并为每个连接打印一条消息。请尝试运行它,然后在浏览器中打开http://127.0.0.1:8080来查看连接。

use tokio::net::TcpListener;

#[tokio::main]
async fn main() {
  let listener = TcpListener::bind("127.0.0.1:8080").await.unwrap();
  println!("Listening on: {}", listener.local_addr().unwrap());

  loop {
    let (socket, addr) = listener.accept().await.unwrap();
    println!("Accepted connection from: {}", addr);
    // In a real server, you'd spawn a task to handle the socket
    // tokio::spawn(async move { handle_connection(socket).await; });
  }
}

// fn handle_connection(socket: TcpStream) { /* ... */ } // Placeholder

Tokio 任务挑战

请思考下面这段使用 Tokio 的 Rust 代码。程序运行时,控制台打印的第一条消息会是什么?

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

#[tokio::main]
async fn main() {
  tokio::spawn(async {
    sleep(Duration::from_millis(200)).await;
    println!("Task 1: Done");
  });

  tokio::spawn(async {
    sleep(Duration::from_millis(100)).await;
    println!("Task 2: Done");
  });

  println!("Main: Starting tasks...");

  sleep(Duration::from_millis(300)).await;
  println!("Main: Finishing.");
}

回顾:使用 Tokio 构建应用

您已经在使用 Rust 和 Tokio 构建异步应用方面迈出了重要一步!

  • Tokio 充当异步运行时,执行您的async代码。
  • #[tokio::main]是程序的异步入口点。
  • tokio::spawn让您能够并发运行多个任务。
  • tokio::join!帮助您等待多个 future。
  • Tokio 为文件(tokio::fs)和网络(tokio::net)提供非阻塞 I/O。

这些工具是使用 Rust 创建高并发、响应迅速的应用的基础。请继续练习!

免费开始

用 AI 导师学习 Rust — 免费

在浏览器中编写并运行真实代码,获得全天候 AI 导师的即时帮助,并在网页或应用中继续学习。

课程
39
课程
144

常见问题解答

「使用 Tokio 构建异步应用」课时是免费的吗?

是的 — 「使用 Tokio 构建异步应用」的完整文本可在网页上免费阅读。要进行交互式练习(内置代码编辑器和全天候 AI 导师)并解锁 Learn Rust Coding 课程的其余内容,请升级到 CoddyKit PRO。 Learn Rust Coding 课程共包含 3 节课。

「使用 Tokio 构建异步应用」这节课中我会学到什么?

使用 Tokio 运行时高效执行异步任务,处理 I/O 和其他并发操作。 你通过在浏览器中直接运行的动手代码来练习 Learn Rust Coding,全天候 AI 导师会在你学习这节课的过程中回答你的问题。

学习 Learn Rust Coding 需要有经验吗?

无需任何先前经验。CoddyKit 上的 Learn Rust Coding 课程适合初学者到高级学习者,你可以从这里开始或从头开始,按照自己的节奏学习。 这是第 2 节课,共 3 节。

「使用 Tokio 构建异步应用」课时需要多长时间?

大多数 CoddyKit 课程大约需要 5–10 分钟。每节课都很精短且互动,所以你能稳步进步,并在网页和应用中从离开的地方继续。

我能在这节 Learn Rust Coding 课中编写并运行代码吗?

能。每节 Learn Rust Coding 课都包含内置代码编辑器,你可以在浏览器中直接编写并运行真实代码,并获得即时 AI 反馈 — 无需本地设置。

此课程中的所有课时

  1. 异步编程与 Async/Await 入门
  2. 使用 Tokio 构建异步应用
  3. 使用 Future 与任务
← 返回 Learn Rust Coding