Rust中的异步编程:构建简单的网页爬虫

一、什么是Rust中的Futures和Async?

在Rust中,异步编程基于future(未来)的概念。一个future表示一个当前可能不可用,但将来某个时候可以获得的值。Rust中的Future特征定义了这一概念,任何实现了该特征的类型都表示一个future。

Rust中的异步编程关键元素包括:

  • asyncasync关键字标记函数或代码块,可以被中断并稍后恢复。当你标记一个函数为async时,它将返回一个Future,而不是直接返回结果。

  • awaitawait关键字用于在async函数中暂停函数的执行,直到待处理的future完成。

1.1.示例:并发地获取网页

让我们创建一个命令行程序,它并发地获取两个网页,提取它们的<title>元素,并打印第一个完成的网页的标题。我们将使用trpl crate,它提供了一个简化Rust异步编程的抽象,封装了像futurestokio这样的常见异步库。

1.2.设置项目

首先,我们需要设置一个新的Rust项目,并将trpl crate作为依赖项。

$ cargo new hello-async
$ cd hello-async
$ cargo add trpl

1.3.第一步:定义page_title函数

为了从网页中获取<title>元素,我们定义一个异步函数page_title。该函数将使用trpl::get方法发送HTTP GET请求到指定的URL并获取网页内容。然后,我们通过CSS选择器提取<title>元素。

这是page_title函数的实现:

use trpl::Html;/// 异步函数,获取指定URL页面的<title>元素
async fn page_title(url: &str) -> Option<String> {// 使用trpl库的get方法获取网页内容,text()方法返回网页的文本内容let response_text = trpl::get(url).await.text().await;// 解析HTML并查找<title>标签,返回标题内容Html::parse(&response_text).select_first("title")  // 使用CSS选择器查找第一个<title>元素.map(|title| title.inner_html())  // 如果找到了<title>,返回其内部HTML内容
}
1.3.1.解释:
  • 我们将函数标记为async,因为我们使用了异步操作,如获取URL (get(url)) 和读取响应体 (text()),这些都是异步操作。
  • get(url)text()都是异步操作,所以我们使用await等待它们完成。
  • 获取到响应后,我们解析HTML并使用select_first("title")方法查找第一个<title>元素。
  • 最后,我们返回<title>元素的内部HTML内容,即页面的标题,返回类型是Option<String>

1.4.第二步:在main函数中调用page_title

接下来,我们需要在main函数中调用page_title函数。然而,Rust不允许将main函数标记为异步函数,因此我们必须使用一个运行时来执行异步代码。我们可以使用trpl::run函数,它初始化异步运行时并运行page_title函数返回的future。

这是更新后的main函数:

fn main() {// 从命令行参数中获取两个URLlet url1 = std::env::args().nth(1).expect("Please provide the first URL");let url2 = std::env::args().nth(2).expect("Please provide the second URL");// 使用trpl::run运行一个异步代码块trpl::run(async {// 创建两个异步任务,分别获取两个URL的<title>元素let title_fut_1 = page_title(&url1);let title_fut_2 = page_title(&url2);// 使用race函数并发地执行两个任务,返回第一个完成的结果let result = trpl::race(title_fut_1, title_fut_2).await;// 根据race函数的结果打印第一个完成的页面标题match result {trpl::Either::Left(Some(title)) => println!("The title for {} is: {}", url1, title),trpl::Either::Right(Some(title)) => println!("The title for {} is: {}", url2, title),_ => println!("Could not fetch title for one or both URLs."),}});
}

1.5.第三步:竞速两个URL

在这个示例中,我们从命令行传入两个URL,分别获取它们的标题,并返回第一个完成的网页。我们使用trpl::race函数,它返回一个值,指示哪个future先完成。

1.5.1解释:
  • 我们并发地调用page_title函数,分别创建两个future:title_fut_1title_fut_2
  • 使用trpl::race等待哪个future先完成。它返回一个值,表示哪个future完成得更早,我们可以根据这个结果处理。
  • 使用match语句打印第一个完成的页面的标题。如果某个页面没有<title>标签,我们也会处理这种情况。

1.6.运行程序

要运行该程序,您需要提供两个URL作为命令行参数。下面是运行爬虫的示例:

$ cargo run -- https://www.rust-lang.org https://www.example.com

输出将显示第一个完成加载的页面的标题:

The title for https://www.rust-lang.org is: Rust Programming Language

1.7.理解Rust中的Async和Futures

在这个示例中,async关键字将函数转换为返回Future的函数,Future代表一个将在未来某个时刻可用的值。这是Rust中异步编程的基本概念。

  • 懒惰的Futures:在Rust中,futures是懒惰的,意味着它们不会在创建时立即执行,而是直到使用await显式等待它们时才会执行。这使得Rust能够优化异步任务并避免不必要的计算。

  • 状态机和执行器:每个async函数都被Rust编译器转换为一个状态机。这些状态机允许程序在await点暂停执行,并在未来某个时刻恢复。异步任务的执行由执行器管理,例如trpl::run函数所提供的执行器。

  • 并发性:通过让两个URL并发执行,我们利用了异步编程的优势,使程序比顺序执行更高效。

二、结论

我们成功地构建了一个简单的异步网页爬虫,能够并发地获取两个网页,并打印第一个完成的网页的标题。在这个过程中,我们学习了Rust中的异步编程的基本概念,包括futures、async/await和并发性。

通过使用trpl crate并理解Rust的异步系统工作原理,你现在可以创建更复杂的异步应用程序,充分利用Rust的并发模型。祝编程愉快!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/27950.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

校园快递助手小程序毕业系统设计

系统功能介绍 管理员端 1&#xff09;登录&#xff1a;输入账号密码进行登录 2&#xff09;用户管理&#xff1a;查看编辑添加删除 学生信息 3&#xff09;寄件包裹管理&#xff1a;查看所有的包裹信息&#xff0c;及物流信息 4&#xff09;待取件信息&#xff1a;查看已到达的…

Docker入门指南:Windows下docker配置镜像源加速下载

Windows下docker配置镜像源加速下载 docker的官方镜像是海外仓库&#xff0c;默认下载耗时较长&#xff0c;而且经常出现断站的现象&#xff0c;因此需要配置国内镜像源。 国内镜像源概述 国内现有如下镜像源可以使用 "http://hub-mirror.c.163.com", "http…

DeepSeek 助力 Vue3 开发:打造丝滑的表格(Table)示例2: 分页和排序

前言:哈喽,大家好,今天给大家分享一篇文章!并提供具体代码帮助大家深入理解,彻底掌握!创作不易,如果能帮助到大家或者给大家一些灵感和启发,欢迎收藏+关注哦 💕 目录 DeepSeek 助力 Vue3 开发:打造丝滑的表格(Table)示例2: 分页和排序📚前言📚页面效果📚指令…

数据结构:二叉树的链式结构及相关算法详解

目录 一.链式结构的实现 1.二叉树结点基本结构&#xff0c;初始化与销毁&#xff1a; 二.链式结构二叉树的几种遍历算法 1.几种算法的简单区分&#xff1a; 2.前序遍历&#xff1a; 3.中序遍历&#xff1a; 4.后序遍历&#xff1a; 5.层序遍历&#xff08;广度优先遍历B…

动态规划/贪心算法

一、动态规划 动态规划 是一种用于解决优化问题的算法设计技术&#xff0c;尤其适用于具有重叠子问题和最优子结构性质的问题。它通过将复杂问题分解为更简单的子问题&#xff0c;并保存这些子问题的解以避免重复计算&#xff0c;从而提高效率。 动态规划的核心思想 最优子结…

【实战篇】【深度解析DeepSeek:从机器学习到深度学习的全场景落地指南】

一、机器学习模型:DeepSeek的降维打击 1.1 监督学习与无监督学习的"左右互搏" 监督学习就像学霸刷题——给标注数据(参考答案)训练模型。DeepSeek在信贷风控场景中,用逻辑回归模型分析百万级用户数据,通过特征工程挖掘出"凌晨3点频繁申请贷款"这类魔…

软考中级-数据库-3.2 数据结构-数组和矩阵

数组 一维数组是长度固定的线性表&#xff0c;数组中的每个数据元素类型相同。n维数组是定长线性表在维数上的扩张&#xff0c;即线性表中的元素又是一个线性表。 例如一维数组a[5][a1,a2,a3,a4,a5] 二维数组a[2][3]是一个2行2列的数组 第一行[a11,a12,a13] 第二行[a21,a22,a23…

android亮灭屏流程分析

前言 亮灭涉及的东西非常多&#xff0c;因此单独写一个文档&#xff0c;进行详细说明&#xff0c;亮灭屏包括的东西不只是亮灭屏&#xff0c;还包括亮度调节、屏幕状态变化等东西。本文仅作学习使用&#xff0c;不涉及商业&#xff0c;侵权请联系删除。 framework层的学习链接…

V4L2框架基础

一、V4L2视频设备驱动基础 1.V4L2是专门为Linux设备设计的整合视频框架&#xff08;其主要核心在Linux内核&#xff0c;相当于Linux操作系统上层的视频源捕获驱动框架&#xff09;。为上层访问系统底层的视频设备提供一个统一的标准接口。V4L2驱动框架能够支持多种类型&#x…

C# 多线程

概述 进程和线程 进程&#xff1a;指在系统中运行的一个应用程序。 线程&#xff1a;进程中的一个执行任务。一个进程至少有一个线程&#xff0c;一个进程可以有多个线程&#xff0c;多个线程可共享数据。 多线程 多线程&#xff1a;在一个程序中同时运行多个线程&#xff0…

突破光学成像局限:全视野光学血管造影技术新进展

全视野光学血管造影&#xff08;FFOA&#xff09;作为一种实时、无创的成像技术&#xff0c;能够提取生物血液微循环信息&#xff0c;为深入探究生物组织的功能和病理变化提供关键数据。然而&#xff0c;传统FFOA成像方法受到光学镜头景深&#xff08;DOF&#xff09;的限制&am…

Deepgram推出Nova-3 Medical,AI语音转录助力医疗行业

每周跟踪AI热点新闻动向和震撼发展 想要探索生成式人工智能的前沿进展吗&#xff1f;订阅我们的简报&#xff0c;深入解析最新的技术突破、实际应用案例和未来的趋势。与全球数同行一同&#xff0c;从行业内部的深度分析和实用指南中受益。不要错过这个机会&#xff0c;成为AI领…

centOS 环境 安装redis方法

一、准备centOS环境 参考文章&#xff1a;Hyper-V 安装CentOS7_代码草率了的博客-CSDN博客 二、redis官网 地址&#xff1a;Download | Redis 演示版本为?redis-5.0.14.tar.gz 三、redis源码编译 登录后创建soft目录 进入目录使用wget下载所需资源包 命令&#xff1a;w…

[51 单片机] --串口编程

1&#xff0c;通讯方式基本概念 1&#xff0c;按照 --> 数据传送方式串行通讯&#xff1a;使用一条数据线&#xff0c;将数据一位一位地依次传输&#xff0c;每一位数据占据一个固定的时间长度&#xff0c;串行通信的特点&#xff1a;传输线少&#xff0c;长距离传送时成本…

Golang的微服务服务发现机制

## 1. Golang微服务服务发现机制 微服务架构已经成为当今软件开发的主流趋势&#xff0c;它能将复杂的单体应用拆分成小而独立的服务单元&#xff0c;实现更快的开发、部署和扩展。在微服务架构中&#xff0c;服务发现是非常重要的一环&#xff0c;它能够实现服务之间的自动发现…

Python 创建地形图

原始地 DEM。 火山口湖 (OR) 区域的起始 DEM。数据来自 NASA DEM 本身非常美丽&#xff0c;但我们先进行分层。 将自定义色彩图应用于 DEM 对于我在 ArcGIS Pro 版本中所做的初始高程样式着色&#xff0c;我使用了“高程 #7”。在 matplotlib 中可用的标准颜色图中&#xff…

《Operating System Concepts》阅读笔记:p180-p187

《Operating System Concepts》学习第 20 天&#xff0c;p180-p187 总结&#xff0c;总计 8 页。 一、技术总结 1.forke-join A strategy for thread creation in which the main parent thread creates (forks) one or more child threads and then waits for the children…

文心4.5,大模型下半场的野心之作

2025年开年&#xff0c;全球大模型竞赛进入白热化阶段。2月28日&#xff0c;百度宣布其文心大模型4.5将于3月16日正式上线&#xff0c;强调其原生多模态与深度思考能力&#xff0c;并计划于6月30日开源。这一动作不仅标志着百度技术路线的重大转向&#xff0c;更被视为中国大模…

transformer架构解析{前馈全连接层,规范化层,子层(残差)连接结构}(含代码)-4

目录 前言 前馈全连接层 学习目标 什么是前馈全连接层 前馈全连接层的作用 前馈全连接层代码实现 规范化层 学习目标 规范化层的作用 规范化层的代码实现 子层&#xff08;残差&#xff09;连接结构 学习目标 什么是子层&#xff08;残差&#xff09;连接结构 子层连…

Django视图与URLs路由详解

在Django Web框架中&#xff0c;视图&#xff08;Views&#xff09;和URLs路由&#xff08;URL routing&#xff09;是Web应用开发的核心概念。它们共同负责将用户的请求映射到相应的Python函数&#xff0c;并返回适当的响应。本篇博客将深入探讨Django的视图和URLs路由系统&am…