【Rust光年纪】并发编程利器:探索 Rust 异步库与并行处理工具
构建高效异步应用:Rust 异步库详细解读
前言
在当今软件开发领域,Rust语言作为一种快速、安全和并发性能出色的编程语言,备受开发者青睐。随着Rust生态系统的不断扩大,越来越多的异步库和并行处理工具被引入到Rust开发中。本文将重点介绍几个在Rust语言中广泛应用的异步库和数据并行处理工具,这些工具可以帮助开发者更加高效地利用多核处理器,并实现安全、高性能的消息传递和共享数据操作。
欢迎订阅专栏:Rust光年纪
文章目录
- 构建高效异步应用:Rust 异步库详细解读
- 前言
- 1. rayon:一个数据并行库
- 1.1 简介
- 1.1.1 核心功能
- 1.1.2 使用场景
- 1.2 安装与配置
- 1.2.1 安装指南
- 1.2.2 基本配置
- 1.3 API 概览
- 1.3.1 并行迭代
- 1.3.2 数据并行操作
- 2. crossbeam:用于多消费多生产环境中的发送技术库
- 2.1 简介
- 2.1.1 核心功能
- 2.1.2 使用场景
- 2.2 安装与配置
- 2.2.1 安装指南
- 2.2.2 基本配置
- 2.3 API 概览
- 2.3.1 多消费者、多生产者通道
- 2.3.2 并发原语
- 3. tokio-postgres:一个用于Rust语言的异步PostgreSQL客户端
- 3.1 简介
- 3.1.1 核心功能
- 3.1.2 使用场景
- 3.2 安装与配置
- 3.2.1 安装指南
- 3.2.2 基本配置
- 3.3 API 概览
- 3.3.1 异步连接管理
- 3.3.2 异步数据操作
- 4. async-std:一个用于Rust语言的异步标准库
- 4.1 简介
- 4.1.1 核心功能
- 4.1.2 使用场景
- 4.2 安装与配置
- 4.2.1 安装指南
- 4.2.2 基本配置
- 4.3 API 概览
- 4.3.1 异步任务管理
- 4.3.2 异步I/O操作支持
- 5. async-graphql:一个用于构建GraphQL服务器的异步库
- 5.1 简介
- 5.1.1 核心功能
- 5.1.2 使用场景
- 5.2 安装与配置
- 5.2.1 安装指南
- 5.2.2 基本配置
- 5.3 API 概览
- 5.3.1 异步GraphQL解析
- 6. shellexpand:用于扩展环境变量和用户目录的路径的库
- 6.1 简介
- 6.1.1 核心功能
- 6.1.2 使用场景
- 6.2 API 概览
- 6.2.1 路径扩展
- 6.2.2 自定义变量扩展
- 总结
1. rayon:一个数据并行库
Rayon 是一个 Rust 语言的数据并行库,旨在提供数据并行操作的能力,以便更高效地利用多核处理器。
1.1 简介
1.1.1 核心功能
Rayon 的核心功能是提供数据并行操作的能力,能够将任务自动分配给可用的处理器核心,并通过适当的线程池管理来执行这些任务。
1.1.2 使用场景
Rayon 适用于需要并行处理大规模数据集的场景,如数据处理、图像处理等。通过 Rayon,可以轻松地编写并行化代码,充分利用多核处理器的计算能力。
1.2 安装与配置
1.2.1 安装指南
要使用 Rayon 库,首先需要在 Cargo.toml 文件中添加 Rayon 的依赖项:
[dependencies]
rayon = "1.5"
引入相应模块:
use rayon::prelude::*;
1.2.2 基本配置
Rayon 的基本配置包括线程池大小、任务分发策略等参数。一般情况下,不需要手动配置,Rayon 会根据当前系统和运行时环境进行自动调优。
1.3 API 概览
1.3.1 并行迭代
Rayon 提供了 par_iter
方法,可以对集合进行并行迭代操作。下面是一个简单的示例:
fn main() {let mut vec = vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10];vec.par_iter_mut().for_each(|x| *x += 1);println!("{:?}", vec);
}
通过 par_iter_mut
方法,可以对向量中的每个元素进行并行修改,提高了处理速度。
1.3.2 数据并行操作
除了并行迭代外,Rayon 还支持数据并行的 map、filter、reduce 等操作。下面是一个使用 Rayon 进行数据并行 map 操作的示例:
fn main() {let mut vec = vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10];let result: Vec<i32> = vec.par_iter().map(|x| x * 2).collect();println!("{:?}", result);
}
在上面的示例中,Rayon 的 par_iter
方法使得对向量中的每个元素进行乘法操作可以并行进行,提高了处理效率。
更多关于 Rayon 的信息,可以访问官方网站:Rayon
2. crossbeam:用于多消费多生产环境中的发送技术库
2.1 简介
2.1.1 核心功能
crossbeam 是一个 Rust 语言下的并发库,提供了多种并发原语和工具,支持在多消费者和多生产者环境下进行安全的消息传递和共享数据操作。
2.1.2 使用场景
适用于需要在多线程环境下进行消息传递和共享数据操作的场景,如并发队列、通道等。
2.2 安装与配置
2.2.1 安装指南
在 Cargo.toml 中添加 crossbeam 的依赖项:
[dependencies]
crossbeam = "0.8"
在代码中引入 crossbeam 模块即可开始使用。
2.2.2 基本配置
可以根据需求选择合适的并发原语和工具,进行相应的配置和使用。
2.3 API 概览
2.3.1 多消费者、多生产者通道
crossbeam 提供了 mpmc::channel 方法,用于创建多消费者、多生产者通道。以下是一个简单的示例:
use crossbeam::channel;fn main() {let (s, r) = channel::unbounded();for i in 0..10 {let s = s.clone();std::thread::spawn(move || {s.send(i).unwrap();});}for _ in 0..10 {println!("Received: {}", r.recv().unwrap());}
}
官网链接:crossbeam
2.3.2 并发原语
crossbeam 支持多种并发原语,如 Mutex、RwLock 等,用于安全地共享数据。以下是一个使用 Mutex 的示例:
use std::sync::{Arc, Mutex};
use std::thread;fn main() {let data = Arc::new(Mutex::new(0));let mut handles = vec![];for _ in 0..10 {let data = Arc::clone(&data);let handle = thread::spawn(move || {let mut data = data.lock().unwrap();*data += 1;});handles.push(handle);}for handle in handles {handle.join().unwrap();}println!("Result: {:?}", data.lock().unwrap());
}
官网链接:crossbeam
3. tokio-postgres:一个用于Rust语言的异步PostgreSQL客户端
3.1 简介
tokio-postgres 是一个为 Rust 语言设计的异步 PostgreSQL 客户端。它建立在 Tokio 框架之上,提供了高效的异步操作方式,并且具有强大的功能和灵活的配置选项。
3.1.1 核心功能
- 提供异步连接管理
- 支持异步数据操作
- 支持复杂的查询和事务管理
- 提供了对 Postgres 数据库的全面访问能力
3.1.2 使用场景
tokio-postgres 适用于需要在 Rust 项目中使用 PostgreSQL 数据库,并且希望利用异步编程模式来提高并发性能的开发场景。
3.2 安装与配置
3.2.1 安装指南
要在 Rust 项目中使用 tokio-postgres,首先需要在项目的 Cargo.toml
文件中添加 tokio-postgres 的依赖:
[dependencies]
tokio-postgres = "0.7"
然后在代码中引入 tokio-postgres 库:
extern crate tokio_postgres;
3.2.2 基本配置
在使用 tokio-postgres 之前,需要确保已经正确配置了 PostgreSQL 数据库,并且拥有相应的连接信息(如数据库地址、用户名、密码等)。
3.3 API 概览
3.3.1 异步连接管理
tokio-postgres 提供了异步连接管理的功能,可以通过 tokio_postgres::connect
方法来建立异步连接,并且可以使用 .await
方法等待连接的建立完成。
use tokio_postgres::{NoTls, Error};#[tokio::main]
async fn main() -> Result<(), Error> {let (client, connection) = tokio_postgres::connect("host=localhost user=postgres dbname=mydb",NoTls,).await?;tokio::spawn(async move {if let Err(e) = connection.await {eprintln!("connection error: {}", e);}});// 使用 client 进行数据库操作Ok(())
}
详细的异步连接管理方法可以参考 tokio-postgres 官方文档
3.3.2 异步数据操作
一旦建立了异步连接,就可以使用 tokio-postgres 进行异步数据操作,比如执行 SQL 查询、更新数据等操作。
use tokio_postgres::{NoTls, Error};#[tokio::main]
async fn main() -> Result<(), Error> {let (client, connection) = tokio_postgres::connect("host=localhost user=postgres dbname=mydb",NoTls,).await?;tokio::spawn(async move {if let Err(e) = connection.await {eprintln!("connection error: {}", e);}});let rows = client.query("SELECT id, name FROM users", &[]).await?;for row in &rows {let id: i32 = row.get(0);let name: &str = row.get(1);println!("id: {}, name: {}", id, name);}Ok(())
}
更多异步数据操作的方法可以查阅 tokio-postgres 官方文档
4. async-std:一个用于Rust语言的异步标准库
4.1 简介
async-std 是一个用于 Rust 语言的异步标准库,它提供了丰富的功能来简化异步编程。通过 async-std,开发者可以轻松地创建和管理异步任务以及进行异步I/O操作。
4.1.1 核心功能
- 异步任务管理
- 异步I/O操作支持
4.1.2 使用场景
async-std 可以应用于需要处理大量并发任务或进行高效的异步I/O操作的场景,例如网络编程、Web 服务等。
4.2 安装与配置
4.2.1 安装指南
要开始使用 async-std,首先需要在项目的 Cargo.toml
文件中添加以下依赖:
[dependencies]
async-std = "1.8"
然后执行以下命令安装 async-std:
$ cargo build
4.2.2 基本配置
在 Rust 项目中引入 async-std 库后,就可以开始使用其中提供的异步功能。
4.3 API 概览
4.3.1 异步任务管理
async-std 提供了一套完善的异步任务管理 API,开发者可以使用 async
和 await
关键字来定义和管理异步任务。
例如,下面是一个简单的异步任务示例:
use async_std::task;async fn hello_async() {println!("Hello, async!");
}fn main() {task::block_on(async {hello_async().await;});
}
更多关于异步任务管理的内容,请参考 async-std 的官方文档。
4.3.2 异步I/O操作支持
async-std 提供了对异步I/O操作的全面支持,包括文件操作、网络通信等。开发者可以通过 async-std 轻松实现高效的异步I/O编程。
以下是一个简单的异步文件读取示例:
use async_std::fs::File;
use async_std::prelude::*;async fn read_file() -> std::io::Result<String> {let mut file = File::open("example.txt").await?;let mut contents = String::new();file.read_to_string(&mut contents).await?;Ok(contents)
}
有关异步I/O操作支持的更多信息,请查阅 async-std 的官方文档。
5. async-graphql:一个用于构建GraphQL服务器的异步库
5.1 简介
async-graphql 是一个用于构建GraphQL服务器的异步库,它提供了一种方便的方式来定义和执行GraphQL 模式。
5.1.1 核心功能
async-graphql 的核心功能包括:
- 异步执行GraphQL查询
- 支持GraphQL模式的定义与解析
- 异步数据加载器
- 自定义中间件
- 错误处理机制
5.1.2 使用场景
async-graphql 可以被广泛用于构建高性能的GraphQL服务器。它适用于Web服务、后端服务等各种异步应用场景。
5.2 安装与配置
5.2.1 安装指南
你可以在 Cargo.toml
文件中添加 async-graphql 作为依赖:
[dependencies]
async-graphql = "4.0"
然后使用 cargo build
命令来安装该库。
5.2.2 基本配置
基本配置包括创建 GraphQL 服务器和定义数据模型。以下是一个简单示例:
use async_graphql::{EmptyMutation, EmptySubscription, Object, Schema, SimpleObject};#[derive(SimpleObject)]
struct User {id: String,name: String,
}struct Query;#[Object]
impl Query {async fn user(&self, id: String) -> User {// 返回用户信息User {id,name: format!("User {}", id),}}
}#[tokio::main]
async fn main() {let schema = Schema::build(Query, EmptyMutation, EmptySubscription).finish();
}
5.3 API 概览
5.3.1 异步GraphQL解析
async-graphql 提供了异步执行GraphQL查询的能力。下面是一个简单的示例代码:
use async_graphql::{Context, EmptyMutation, EmptySubscription, Object, Schema, SimpleObject};// 定义数据模型
#[derive(SimpleObject)]
struct User {id: String,name: String,
}// 查询对象
struct Query;#[Object]
impl Query {async fn user(&self, id: String) -> User {// 返回用户信息User {id,name: format!("User {}", id),}}
}#[tokio::main]
async fn main() {// 创建并运行 GraphQL 服务器let schema = Schema::build(Query, EmptyMutation, EmptySubscription).finish();// 执行查询let query = r#"{user(id: "123") {idname}}"#;let result = schema.execute(query).await;println!("{:?}", result);
}
更多详情请参考 async-graphql官网。
6. shellexpand:用于扩展环境变量和用户目录的路径的库
6.1 简介
shellexpand 是一个用于扩展环境变量和用户目录路径的 Rust 库。它允许用户将包含环境变量或用户目录(如~)的路径字符串转换为绝对路径。
6.1.1 核心功能
shellexpand 的核心功能是扩展包含环境变量和用户目录的路径字符串,将其转换为实际的绝对路径,以便进行文件操作等操作。
6.1.2 使用场景
使用 shellexpand 可以方便地处理包含环境变量和用户目录的路径,使其能够被程序正确识别并使用。
6.2 API 概览
shellexpand 库提供了以下主要功能:
6.2.1 路径扩展
通过 shellexpand,可以将包含环境变量的路径字符串扩展为实际的绝对路径。下面是一个示例代码:
use shellexpand::tilde;fn main() {let path_str = "~/Documents/file.txt";let expanded_path = shellexpand::tilde(path_str);println!("Expanded Path: {}", expanded_path);
}
官网链接:shellexpand
6.2.2 自定义变量扩展
除了环境变量和用户目录的扩展外,shellexpand 还支持自定义变量的扩展。下面是一个示例代码:
use shellexpand::full_with_context;
use std::collections::HashMap;fn main() {let mut variables = HashMap::new();variables.insert("MY_DIR", "/path/to/my/directory");let path_str = "$MY_DIR/file.txt";let expanded_path = shellexpand::full_with_context(path_str, |var| {variables.get(var).map(|v| v.as_ref())});println!("Expanded Path: {}", expanded_path);
}
官网链接:shellexpand
通过以上示例代码,可以看到 shellexpand 提供了方便的方法来处理路径中的环境变量和自定义变量,使得路径处理更加灵活和便捷。
总结
通过本文的介绍,读者可以深入了解到在Rust语言中用于并行处理和异步编程的关键工具和库。这些工具和库不仅能够帮助开发者更好地利用硬件资源,提高程序的性能和并发能力,同时也能够简化异步编程的复杂性,提升开发效率。对于需要处理大规模数据集、构建高性能异步应用或构建GraphQL服务器的开发者来说,本文介绍的内容将会是非常有益的。
相关文章:

【Rust光年纪】并发编程利器:探索 Rust 异步库与并行处理工具
构建高效异步应用:Rust 异步库详细解读 前言 在当今软件开发领域,Rust语言作为一种快速、安全和并发性能出色的编程语言,备受开发者青睐。随着Rust生态系统的不断扩大,越来越多的异步库和并行处理工具被引入到Rust开发中。本文将…...

机器学习第一课
1.背景 有监督学习:有标签(连续变量(回归问题:时间序列等)、分类变量(分类)) 无监督学习:没有标签(聚类、关联(相关性分析:哪些相关…...

C语言典型例题32
《C程序设计教程(第四版)——谭浩强》 习题2.9 编程序用getchar函数读入两个字符给c1,c2,然后分别用putchar函数和printf函数输出这两个字符。 (1)变量c1,c2应该定义为字符型或者整型吗&#x…...

第二十五天学习笔记2024.8.9
1、通过frp内网穿透共享数据库信息 [root1 ~]# mysql -p密码 mysql> create user li% identified by 1; mysql> create database test; mysql> grant all on test.* to li; [root1 ~]# tar -xf frp_0.33.0_linux_amd64.tar.gz [root1 ~]# cd frp_0.33.0_linux_a…...

sqlserver将一张表导出成txt
bcp zjwb_sb_20111122.dbo.ep_pb_groupvisitplace out c:/1.txt -n -U sa -P sa...

YOLOv8+DeepSort实现
目录 1,YOLOv8算法简介 2,DeepSort算法介绍 1. SORT目标追踪 3,实现流程 1.检测 2. 生成detections 3. 卡尔曼滤波预测 4.使用匈牙利算法将预测后的tracks和当前帧中的detections进行匹配 5. 卡尔曼滤波更新 4,代码实现 …...

「链表」链表原地算法合集:原地翻转|原地删除|原地取中|原地查重 / LeetCode 206|237|2095|287(C++)
概述 对于一张单向链表,我们总是使用双指针实现一些算法逻辑,这旨在用常量级别空间复杂度和线性时间复杂度来解决一些问题。 所谓原地算法,是指不使用额外空间的算法。 现在,我们利用双指针实现以下四种行为。 //Definition fo…...

【STM32】SPI通信和RTC实时时钟
个人主页~ SPI通信和RTC实时时钟 SPI通信一、简介二、硬件电路三、基本原理四、SPI时序1、时序基本单元2、时序 五、FLASH操作注意事项1、写入操作2、读取操作 六、SPI外设1、简介2、结构 七、传输方式1、主模式全双工连续传输2、非连续传输 RTC实时时钟一、Unix时间戳二、BKP1…...

DAMA学习笔记(十三)-大数据和数据科学
1.引言 大数据不仅指数据的量大,也指数据的种类多(结构化的和非结构化的,文档、文件、音频、视频、流数据等),以及数据产生的速度快。数据科学家是指从从数据中探究、研发预测模型、机器学习模型、规范性模型和分析方法…...

【Java】Java 中的 toLowerCase() 方法详解
我最爱的那首歌最爱的angel 我到什么时候才能遇见我的angel 我最爱的那首歌最爱的angel 我不是王子也会拥有我的angel 🎵 张杰《云中的angel》 在 Java 编程中,字符串处理是一个非常常见的任务。为了便于开发者操作和格式化字符串&…...

Linux: 进程概念详解
1. 冯诺依曼体系结构 截至目前,我们所认识的计算机,都是有一个个的硬件组件组成 。 【注意】: a. 这里的存储器指的是内存 b. 不考虑缓存情况,这里的CPU能且只能对内存进行读写,不能访问外设(输入或输出设备) c.外…...

【C++】模板详细讲解(含反向迭代器)
欢迎来到我的Blog,点击关注哦💕 前言: C的模板在是泛型编程的重要组成部分,编写在不同类型上工作的代码,而无需为每个类型编写重复的代码,这有助于减少代码冗余并提高代码的可维护性。 模板 模板的介绍 …...

haproxy七层代理详解之-完整安装部署流程及负载均衡实现-及热更新方法
一.负载均衡 1.1负载均衡时什么 负载均衡:Load Balance,简称LB,是一种服务或基于硬件设备等实现的高可用反向代理技术,负载均网络流量等)分担给指定的一个或多个后端特定的服务器或设备,从而提高了衡将特定的业务(web服务、公司…...

C++11 bind
bind bind 用来将可调用对象和参数一起进行绑定。可调用对象包括普通函数、全局函 数、静态函数、类静态函数甚至是类成员函数,参数包括普通参数和类成员。绑定后的 结果,可以使用 std::function 进行保存,并延迟调用到我们需要的时候。 绑…...

LeetCode199 二叉树的右视图
前言 题目: 199. 二叉树的右视图 文档: 代码随想录——二叉树的右视图 编程语言: C 解题状态: 成功解决! 思路 二叉树层序遍历问题的变种,右视图即意味着二叉树每层的最后一个节点。 代码 /*** Definiti…...

数据赋能(172)——开发:数据挖掘——影响因素、直接作用、主要特征
影响因素 主要影响因素如下: 数据类型与属性: 数据类型和对象的不同属性会使用不同的数据类型来描述,如年龄可能是整数类型,而生日则是日期类型。数据挖掘时需要对不同的数据类型进行不同的处理,这直接影响到挖掘算法…...

Vue:Vue3-TypeScript-Pinia-Vite-pnpm / 基础项目 / 20240807
一、项目技术栈 / 依赖 序号技术栈版本解释1node20.14.02vue 3.4.31 3vite 5.3.4 4TypeScript 5.2.2 5 types/node 22.0.2 解决TypeScript项目中缺少对应模块的类型定义文件的问题6 element-plus 2.7.8 ui组建7 types/js-cookie js-cookie 3.0.6 3.0.5 8 sass 1.77.8 9 hu…...

windows Qt 录屏 录音
启动录屏录音: connect(&m_Process, &QProcess::readyReadStandardOutput, [&]() {qDebug() << "Standard output:" << QString::fromLocal8Bit(m_Process.readAllStandardOutput()); });connect(&m_Process, &QProcess…...

AAC中的ADTS格式分析
😎 作者介绍:欢迎来到我的主页👈,我是程序员行者孙,一个热爱分享技术的制能工人。计算机本硕,人工制能研究生。公众号:AI Sun(领取大厂面经等资料),欢迎加我的…...

iOS内存管理---MRC vs ARC
系列文章目录 iOS基础—Block iOS基础—Protocol iOS基础—KVC vs KVO iOS网络—AFNetworking iOS网络—NSURLSession iOS内存管理—MRC vs ARC iOS基础—Category vs Extension iOS基础—多线程:GCD、NSThread、NSOperation iOS基础—常用三方库:Mason…...

【数学分析笔记】第1章第1节:集合(2)
这节我自己补了一些内容,要不然听不太懂陈纪修老师讲的 1. 集合与映射 1.3 子集与真子集 假如有 S \textbf{S} S和 T \textbf{T} T两个集合,其中, S \textbf{S} S的所有元素都属于 T \textbf{T} T,则称 S \textbf{S} S是 T \te…...

大话设计模式:七大设计原则
目录 一、单一职责原则(Single Responsibility Principle, SRP) 二、开放封闭原则(Open-Closed Principle, OCP) 三、依赖倒置原则(Dependency Inversion Principle, DIP) 四、里氏替换原则&am…...

利用多商家AI智能名片小程序提升消费者参与度与个性化体验:重塑零售行业的忠诚策略
摘要:在数字化浪潮席卷全球的今天,零售行业正经历着前所未有的变革。消费者对于购物体验的需求日益多样化、个性化,而零售商则面临着如何将一次性购物者转化为品牌忠诚者的巨大挑战。多商家AI智能名片小程序作为一种新兴的数字营销工具&#…...

Scala 闭包
Scala 闭包 Scala 闭包是一个非常重要的概念,它允许我们创建可以在稍后某个时间点执行的功能片段。闭包是一个函数,它捕获了封闭范围内的变量,即使在函数外部,这些变量也可以在函数内部使用。这使得闭包成为处理异步操作、回调和…...

前端JS总结(中)
目录 前言 正文 对象: 分类: 自定义对象: 内置对象: 重点: 常用内置对象: 字符串对象:String 获取字符串长度: 大小写转换: 获取某个字符: 截取字…...

elasticsearch的match_phrase匹配及其可能导致的查询问题
目录 1.match_phrase使用介绍 2.规避可能产生的查询问题 解决方式 一.查询和索引分词器一致,即都使用max_word或者都使用smart 二.使用slop增加匹配的容忍度 3.参考文档 1.match_phrase使用介绍 elasticsearch的match_phrase查询是全文查询,主要用…...

C++快速理解之继承
一、继承和派生 1.是什么? C 中的继承是类与类之间的关系,与现实世界中的继承类似 例如:儿子继承父亲的财产 继承(Inheritance)可以理解为一个类从另一个类获取成员变量和成员函数的过程 例如: 类B继承…...

Node.JS - 基础(Express)
目录 A. 简介 B. 下载,安装 C. 启动服务,查看文件结构 A. 简介 Express 是一个基于 Node.js 平台的极简、灵活的 Web 应用开发框架,它提供了一系列强大的功能来构建 Web 应用程序和 API。 一、Express 的基本特点 简洁的路由系统: Express 的路由系…...

I/O复用
I/O复用使得程序能够同时监听多个文件描述符,这对提高程序的性能至关重要。 举个例子: 就好比你天天玩手机,你妈为了监控你,在你房间安装了一个监控,这个监控可以实时监控你的一举一动,并上传到你妈手机上…...

【验证可用】解决安装SQL Server数据库时,报错“启用 windows 功能 NetFx3 时出错,错误代码:-2146498298......“的问题
目录 背景一. 报错信息1.1 报错的图片信息1.2 报错的文字信息 二. 解决报错2.1 下载 NetFx3.cab 文件2.2 执行命令 三. SQL Server 修复安装 背景 一次在阿里云服务器安装 SQL Server 2012时,系统报错了,导致安装进行不下去…通过在网上查找了多种解决方…...