Rust Async 并发编程:任务、消息传递与 `join`

news/2025/3/6 4:35:08/

1. 创建异步任务

在传统的多线程模型中,我们使用 std::thread::spawn 来创建新的线程。而在 async 模型中,使用 spawn_task 代替 thread::spawn 来创建异步任务,并结合 await 关键字来处理异步操作。

示例:使用 spawn_task 进行并发计算

rust">use trpl::{spawn_task, sleep};
use std::time::Duration;#[tokio::main]
async fn main() {let handle = spawn_task(async {for i in 1..=5 {println!("hi number {} from the second task!", i);sleep(Duration::from_millis(500)).await;}});for i in 1..=5 {println!("hi number {} from the first task!", i);sleep(Duration::from_millis(500)).await;}handle.await.unwrap();
}

运行结果(实际输出顺序可能不同):

hi number 1 from the second task!
hi number 1 from the first task!
hi number 2 from the first task!
hi number 2 from the second task!
...

在该示例中,我们创建了一个新的异步任务 spawn_task,并在主任务中执行另一个循环。因为 sleepasync 版本的,所以 await 允许其他任务在 sleep 期间继续执行,而不会阻塞整个线程。

2. 使用 join 让多个任务同时运行

当我们想要同时运行多个 async 任务并等待它们全部完成时,可以使用 trpl::join。它类似于 std::thread::JoinHandle::join(),但适用于 async 任务。

示例:使用 trpl::join 运行两个异步任务

rust">use trpl::{join, sleep};
use std::time::Duration;#[tokio::main]
async fn main() {let fut1 = async {for i in 1..=5 {println!("Task 1: {}", i);sleep(Duration::from_millis(500)).await;}};let fut2 = async {for i in 1..=5 {println!("Task 2: {}", i);sleep(Duration::from_millis(500)).await;}};join!(fut1, fut2).await;
}

输出顺序保持一致

Task 1: 1
Task 2: 1
Task 1: 2
Task 2: 2
...

相比于 spawn_tasktrpl::join 提供了更加确定的执行顺序,因为 join! 会公平地轮询任务,使得它们不会出现一个任务远远领先于另一个的情况。

3. 通过消息通道在任务间传递数据

std::mpsc::channel 类似,Rust 也提供了 trpl::channel 来进行异步消息传递。这种方式避免了共享内存带来的数据竞争问题。

示例:异步消息传递

rust">use trpl::{channel, sleep};
use std::time::Duration;#[tokio::main]
async fn main() {let (tx, mut rx) = channel();let sender = async move {let messages = vec!["Hello", "from", "the", "async", "world!"];for msg in messages {tx.send(msg).await.unwrap();sleep(Duration::from_millis(500)).await;}};let receiver = async move {while let Some(msg) = rx.recv().await {println!("Received: {}", msg);}};trpl::join(sender, receiver).await;
}

输出

Received: Hello
Received: from
Received: the
Received: async
Received: world!

任务自动关闭

上面的代码能正确终止,因为 txasync move 块结束时会被 drop,从而让 rx.recv() 返回 None,结束 while let 循环。

如果我们希望多个任务发送数据,只需 clone 发送端:

rust">let tx1 = tx.clone();
let sender1 = async move {tx1.send("Extra message").await.unwrap();
};

使用 trpl::join3 让多个任务并发执行。

4. 总结

  • spawn_task 用于创建新的异步任务。
  • await 允许任务在等待时释放 CPU 资源,提高并发性能。
  • trpl::join 确保多个任务公平执行。
  • trpl::channel 实现了异步消息传递,避免了数据竞争。
  • async move 确保所有权正确传递,避免任务执行过程中 tx 被持有过久导致 rx.recv() 无限等待。

Rust 的异步编程提供了强大的并发能力,同时通过 await 避免了传统多线程编程的阻塞问题,使得代码更高效、更易读。希望本文能帮助你更好地理解 async 并发编程的核心概念!


http://www.ppmy.cn/news/1576980.html

相关文章

Python在NFT市场中的应用:从创建到交易的完整指南

Python在NFT市场中的应用:从创建到交易的完整指南 大家好,我是Echo_Wish。今天我们来聊聊一个近年来备受关注的话题——NFT(非同质化代币)。NFT的出现不仅为数字艺术家和收藏家带来了全新的机会,也为开发者提供了一个…

MySQL之 NoneType object has no attribute cursor

查下MySQL报错日志 首先,看下日志文件所在位置 SHOW GLOBAL VARIABLES LIKE log_error;然后查看日志文件中当时的报错信息 发现这样的日志: Aborted connection … to db … Got timeout reading communication packets初步猜测是,数据库…

从零搭建Tomcat:深入理解Java Web服务器的工作原理

Tomcat是Java生态中最常用的Web服务器之一,广泛应用于Java Web应用的部署和运行。本文将带你从零开始搭建一个简易的Tomcat服务器,深入理解其工作原理,并通过代码实现一个基本的Servlet容器。 1. Tomcat的基本概念 Tomcat是一个开源的Servl…

美丽的2024【算法赛】

1.美丽的2024【算法赛】 - 蓝桥云课 问题描述 小蓝刚学习完二进制知识,所以现在他对任何数字的二进制都特别感兴趣。恰好即将迎来2024年,他想知道2024的二进制中有几个1?请你帮忙解决这个问题。 输入格式 本题为填空题,无输入…

三维数据可视化与表面重建:Marching Cubes算法的原理与应用

1. 引言 随着现代医学影像技术的飞速发展,三维数据的可视化与重建已成为医学研究、临床诊断和手术规划的重要工具。在众多三维重建算法中,Marching Cubes算法因其高效、稳定的特性成为从离散数据场中提取等值面的经典方法。本报告将深入探讨Marching Cu…

PyTorch 的 nn.NLLLoss:负对数似然损失全解析

PyTorch 的 nn.NLLLoss:负对数似然损失全解析 在 PyTorch 的损失函数家族中,nn.NLLLoss(Negative Log Likelihood Loss,负对数似然损失)是一个不太起眼但非常重要的成员。它经常跟 LogSoftmax 搭配出现,尤…

读写分离架构下的一致性挑战

读写分离架构下的一致性挑战 什么是读写分离架构读写分离架构的一致性挑战主从复制延迟事务不一致 主从切换导致的数据丢失跨表/跨库操作的一致性问题缓存与数据库的一致性问题查询路由策略不当导致的问题全局二级索引的一致性问题历史查询与实时数据的一致性分布式锁与读写分离…

Transformer 代码剖析9 - 解码器模块Decoder (pytorch实现)

一、模块架构全景图 1.1 核心功能定位 Transformer解码器是序列生成任务的核心组件,负责根据编码器输出和已生成序列预测下一个目标符号。其独特的三级注意力机制架构使其在机器翻译、文本生成等任务中表现出色。下面是解码器在Transformer架构中的定位示意图&…