当前位置: 首页 > news >正文

Flutter中的Future和Stream

在 Flutter 中,FutureStream 都是用于处理异步操作的类,它们都基于 Dart 的异步编程模型,但是它们的使用场景和工作方式有所不同。以下是它们的区别以及各自适用的场景。

目录

    • 一、Future
      • 1、基本使用
      • 2、异常处理
        • 1. catchError
        • 2. onError
        • 3、`catchError` 和 `onError` 的区别
        • 4. 捕获多个错误
        • 5. 错误的传播
      • 总结
    • 二、Stream
      • 1、基本使用
      • 2、异常处理
        • 1. `onError` 处理器
        • 2. `try-catch` 语句
        • 3. 异常后流的状态
        • 4. 流的中断
        • 5. 恢复流
        • 6. 流异常的示例
      • 总结
    • 三、 结合使用 `Future` 和 `Stream`
    • 四、总结
      • 1、区别
      • 2、选择 `Future` 还是 `Stream`
    • 四、疑问
      • 1、Stream 流是按照顺序执行的吗?
        • 1. 顺序性
        • 2. 顺序的保证
      • 2、Stream async* 和 yield 的解释这三个必须要配套使用吗?,不适用 yield 行吗?
        • 1. `Stream` 与 `async*`
        • 2. `async*` 和 `yield` 必须配合使用吗?
        • 3. 不使用 `yield` 行不行?
        • 4. 如何使用 `async*` 生成异步数据流?
        • 总结

一、Future

1、基本使用

Future 是一个表示一个可能还未完成的异步操作的对象。它表示一个将来某个时间点会返回一个结果或错误的计算。

  • 特点
    • Future 代表的是一个 单次 异步操作。
    • 只能返回一次结果或错误,不会再有后续的值。
    • 在调用时,它会返回一个 Future 对象,可以通过 thenawait 等方法获取结果。
    • 如果操作失败,可以通过 catchErroronError 进行错误处理。
  • 使用场景
    • 当你需要等待一个单一的异步结果时,使用 Future
    • 比如从网络获取数据,执行一个数据库查询,或读取一个文件等一次性的操作。
  • 示例代码
// 使用 Future 的示例
Future<String> fetchData() async {// 模拟异步操作await Future.delayed(Duration(seconds: 2));return "Data fetched successfully!";
}void main() async {try {String data = await fetchData();print(data); // 输出 "Data fetched successfully!"} catch (e) {print("Error: $e");}
}

在上面的示例中,fetchData 返回一个 Future<String>,它表示一个将来完成的异步操作。使用 await 来等待这个操作完成并获得结果。

2、异常处理

1. catchError

catchError 是用于捕获和处理 Future 发生错误的一种方式。当 Future 执行失败时,它会触发传给 catchError 的回调函数。这个回调函数可以接受错误和栈跟踪信息。

示例:

Future<int> divide(int a, int b) {return Future.delayed(Duration(seconds: 1), () {if (b == 0) {throw Exception('Cannot divide by zero!');}return a ~/ b;});
}void main() {divide(10, 0).catchError((e) {print('Error: $e');});// Output: Error: Exception: Cannot divide by zero!
}

在这个例子中,当 b 为 0 时,Future 会抛出一个 Exception,并且 catchError 捕获并打印这个错误。

catchError 的用法细节:

  • 返回值的传递catchError 会继续执行 Future 链中的后续操作,因此如果你想在错误发生时返回一个默认值,可以在 catchError 中指定。
Future<int> divide(int a, int b) {return Future.delayed(Duration(seconds: 1), () {if (b == 0) {throw Exception('Cannot divide by zero!');}return a ~/ b;}).catchError((e) {print('Handled error: $e');return -1;  // 返回默认值});
}void main() async {var result = await divide(10, 0);print('Result: $result');  // 输出: Handled error: Exception: Cannot divide by zero!//         Result: -1
}
2. onError

onErrorFuture 的另一种错误处理方式。它与 catchError 类似,但它是 Future 构造函数的一部分,通常用于直接在 Future 构造时附加错误处理。

示例:

Future<int> divide(int a, int b) {return Future.delayed(Duration(seconds: 1), () {if (b == 0) {throw Exception('Cannot divide by zero!');}return a ~/ b;}).onError((error, stackTrace) {print('Caught an error: $error');return -1;  // 返回默认值});
}void main() async {var result = await divide(10, 0);print('Result: $result');  // 输出: Caught an error: Exception: Cannot divide by zero!//         Result: -1
}
3、catchErroronError 的区别
  • catchError 是用于捕获在 Future 执行时抛出的异常,它通常用于链式调用中捕获错误。
  • onErrorFuture 的一种附加错误处理机制,它将错误处理直接嵌入到 Future 构造中。

尽管 catchErroronError 都可以捕获错误并返回一个默认值或执行某些操作,但 catchError 更灵活,通常在复杂的异步链式操作中使用。

4. 捕获多个错误

如果你需要捕获多个错误,可以将 catchErroronError 绑定到多个 Future 链条上。这样可以对不同类型的错误进行不同的处理。

示例:

Future<void> asyncFunction() {return Future.delayed(Duration(seconds: 1), () {throw Exception('Something went wrong!');});
}void main() {asyncFunction().catchError((e) {print('Caught error: $e');}).catchError((e) {print('Another handler for errors: $e');});// Output: Caught error: Exception: Something went wrong!
}
5. 错误的传播

如果在 Future 中没有处理错误,错误将会被传播,直到被外部捕获或程序崩溃。因此,适当的错误处理不仅可以帮助捕获问题,还可以避免未捕获的异常导致程序崩溃。

总结

在 Dart 中,catchErroronError 都可以用于处理异步操作中的错误。它们的主要区别在于用法和灵活性,选择哪一个取决于你的代码结构和需求。

二、Stream

1、基本使用

Stream 是一个表示一系列异步事件的对象,它允许你在未来的时间点接收多个值。

  • 特点
    • Stream 代表的是 多个异步事件
    • 它会按顺序提供一系列的结果(可以是零个或多个),通常用于处理实时数据流。
    • 可以是单向的,也可以是广播流(多个监听者可以订阅)。
    • 你可以通过 listen 方法来监听事件流。
    • Stream 还支持 await for 语法,可以等待并处理每个事件。
  • 使用场景
    • 当你需要处理一个 数据流多个值 时,使用 Stream
    • 比如处理实时数据(如 WebSocket 数据流、用户输入事件流、文件变化等)。
  • 示例代码
// 使用 Stream 的示例
Stream<int> generateNumbers() async* {for (int i = 0; i < 5; i++) {await Future.delayed(Duration(seconds: 1));yield i; // 每秒产生一个数字}
}void main() async {await for (var number in generateNumbers()) {print(number); // 输出:0, 1, 2, 3, 4}
}

在这个示例中,generateNumbers 返回一个 Stream<int>,它每秒返回一个整数。通过 await for 循环,我们可以逐个接收流中的数据。

2、异常处理

当流中发生异常时,有几种方式来处理这些异常,使得流能够继续工作或适当地终止。

1. onError 处理器

如果你使用 Stream.listen 方法来监听流,可以通过传入 onError 回调来处理流中的异常。当流抛出异常时,onError 处理器会被触发。

Stream<int> generateNumbersWithError() async* {yield 1;yield 2;throw Exception('Something went wrong');yield 3;  // 这一行永远不会执行
}void main() {generateNumbersWithError().listen((data) {print('Received: $data');},onError: (error) {print('Caught error: $error');},onDone: () {print('Stream is done');},);
}

输出:

Received: 1
Received: 2
Caught error: Exception: Something went wrong
Stream is done

在这个例子中,当 Stream 中的 Exception 被抛出时,onError 回调会捕获并打印出错误信息。yield 3 后的代码不会执行,因为流在抛出异常后被中断。

2. try-catch 语句

在异步生成器(如 async*)中,你可以使用 try-catch 来捕获异常,这可以防止异常导致流中断。

Stream<int> generateNumbersWithErrorHandled() async* {try {yield 1;yield 2;throw Exception('Something went wrong');yield 3;  // 这一行不会执行} catch (e) {print('Caught error: $e');}
}void main() async {await for (var data in generateNumbersWithErrorHandled()) {print('Received: $data');}
}

输出:

Received: 1
Received: 2
Caught error: Exception: Something went wrong

在这个例子中,即使抛出异常,Stream 仍然能够继续执行,只是异常会被捕获并处理。

3. 异常后流的状态

Stream 抛出异常后,流会进入错误状态,并且不再发出任何数据,除非你有合适的机制来恢复流。

  • 如果流中的 onError 回调没有捕获异常,流会直接终止。
  • 如果你在 Stream 中使用 try-catch 捕获了异常,流可以继续正常工作,继续发送后续的数据。
4. 流的中断

流的中断意味着流不再继续发出事件。中断的原因通常有以下几种:

  • 异常抛出:如果流中的某个操作抛出了异常,流会被中断,后续的事件不会再触发。
  • 用户主动取消订阅:如果你使用 StreamSubscription 来订阅流,并主动调用 cancel(),流也会中断。
  • 流结束:如果流完成(即没有更多的事件要发出),流会进入完成状态。
5. 恢复流

如果你希望在流发生异常后恢复流的工作,可以通过重新订阅流或使用一些复合的错误处理机制。

例如,在监听流时使用 onError 捕获错误并在错误发生时重新启动流:

Stream<int> generateNumbersWithError() async* {yield 1;yield 2;throw Exception('Something went wrong');yield 3;
}void main() {Stream<int> stream = generateNumbersWithError();stream.listen((data) {print('Received: $data');},onError: (error) {print('Caught error: $error');// 重新启动流stream.listen((data) => print('Retry received: $data'),onError: (e) => print('Retry error: $e'),onDone: () => print('Retry stream is done'),);},onDone: () => print('Stream is done'),);
}

在这种情况下,流会在错误发生时重新启动。这允许你捕获错误并尝试恢复流的执行。

6. 流异常的示例

假设有一个 Stream 生成器,它在生成某个事件时发生异常:

Stream<int> generateNumbersWithError() async* {yield 1;yield 2;throw Exception('Unexpected error');yield 3;  // 这行永远不会执行
}void main() async {try {await for (var number in generateNumbersWithError()) {print('Received: $number');}} catch (e) {print('Caught error: $e');}
}

输出:

Received: 1
Received: 2
Caught error: Exception: Unexpected error

在这个例子中,异常会导致流中断,后续的事件不会被处理,且异常被捕获。

总结

  • 流中断:当流遇到异常时,流会进入错误状态并停止发出事件。
  • 异常处理:你可以通过 onError 回调或 try-catch 语句捕获和处理异常。
  • 恢复流:在流发生异常时,可以选择恢复流的工作,例如通过重新订阅流。

三、 结合使用 FutureStream

在某些情况下,FutureStream 可以结合使用。例如,如果你有一个 Future 返回一个数据集,而这个数据集可以被逐步处理,那么你可以将 Future 的结果转换成一个 Stream 来进行逐项处理。

Future<List<int>> fetchData() async {return [1, 2, 3, 4, 5];
}Stream<int> fetchDataAsStream() async* {List<int> data = await fetchData();for (var item in data) {yield item;}
}void main() async {await for (var number in fetchDataAsStream()) {print(number); // 输出 1, 2, 3, 4, 5}
}

在这个例子中,fetchData 是一个 Future,而 fetchDataAsStream 将其转换成了一个 Stream,使得我们能够以流的形式逐项处理数据。

总结

  • Future 适合用于处理 单次 的异步操作,返回一个值或错误。
  • Stream 适合用于处理 多次 的异步事件或数据流,允许你持续接收多个值。

了解它们的区别和使用场景可以帮助你更好地选择异步操作的方式,从而提高代码的可读性和性能。

四、总结

1、区别

特性FutureStream
返回值只返回一个值或一个错误持续返回多个值或错误
生命周期一次性操作,完成后不再有新的值持续发出多个值(或者是事件)
异步操作适用于单次异步操作适用于多次异步事件或数据流
操作方式thencatchErrorawaitlistenawait foraddaddError

2、选择 Future 还是 Stream

  • 使用 Future
    • 你在处理一个单次的异步操作时。
    • 比如从网络获取数据、计算结果、执行数据库操作等。
    • 示例:登录请求、获取单个 API 响应、读取文件内容。
  • 使用 Stream
    • 当你需要处理 多个异步事件,例如实时数据流或变化时。
    • 比如 WebSocket 消息、实时位置更新、文件读取(大文件分片)等。
    • 示例:实时聊天消息、连续的数据更新、传感器数据流等。

四、疑问

1、Stream 流是按照顺序执行的吗?

是的,Stream 在 Dart 中是 按顺序 执行的。具体来说,Stream 中的事件(数据或错误)会按照它们被 产生发出 的顺序进行传递和处理。

1. 顺序性

在 Dart 中,Stream 会按照 事件发出的顺序 将这些事件传递给订阅者。也就是说,先发出的事件会先被监听器处理。

例如,如果你有一个 Stream 生成数据流,并且在每个数据项之间有延时,那么监听器将会按照数据产生的顺序处理每个事件。

示例代码:顺序执行的 Stream

Stream<int> generateNumbers() async* {for (int i = 0; i < 3; i++) {await Future.delayed(Duration(seconds: 1));  // 模拟延时yield i;  // 按顺序发出数据}
}void main() async {await for (var number in generateNumbers()) {print('Received: $number');  // 按顺序输出}
}

输出:

Received: 0
Received: 1
Received: 2

在这个例子中,数据流是按顺序传递给监听器的,即 012 按照生成的顺序被逐个输出。

2. 顺序的保证

Stream 本身的设计保证了事件的顺序。无论你是通过 await for 或者 listen 来处理事件,事件会按照发出顺序依次传递给你。

通过 listen 监听的顺序

Stream<int> generateNumbers() async* {for (int i = 0; i < 3; i++) {await Future.delayed(Duration(seconds: 1));yield i;}
}void main() {generateNumbers().listen((data) {print('Received: $data');  // 按顺序输出});
}

这段代码会输出:

Received: 0
Received: 1
Received: 2

如上所示,数据按照顺序传递。

2、Stream async* 和 yield 的解释这三个必须要配套使用吗?,不适用 yield 行吗?

在 Dart 中,Streamasync*yield 是紧密关联的,但它们不一定是必须同时使用的。它们之间的关系可以分开解释,看看如何组合使用,或者是否可以在没有 yield 的情况下使用 async*

1. Streamasync*

Stream 是 Dart 中用于处理异步数据流的核心概念。Stream 对象用于处理一系列异步事件,而 async* 是定义异步生成器(异步迭代器)的一种语法。async* 允许你生成一个 Stream,并通过 yield 来发出数据。

  • async* 标识一个异步生成器函数,它返回一个 Stream
  • yield 用于在异步生成器中逐个发出数据。
2. async*yield 必须配合使用吗?
  • async*yield 一般是配套使用的,但你也可以只使用 async*,并没有强制要求一定要用 yield
  • 如果你不需要发出数据(即你不想使用 yield),你也可以用 async* 作为一个简单的异步函数来返回一个空的 Stream,或者使用 await 来发出异步的结果。
3. 不使用 yield 行不行?

是的,可以在没有 yield 的情况下使用 async*,但通常这样做的结果是流不会发出任何数据。在这种情况下,Stream 会是一个空的流,或者说它在没有任何数据的情况下完成。

示例 1:不使用 yield,生成一个空的流

Stream<int> generateEmptyStream() async* {// 什么都不发出
}void main() async {await for (var value in generateEmptyStream()) {print(value);  // 这里不会有任何输出}
}

在这个例子中,async* 只是声明了一个异步生成器,但是没有 yield,因此返回的 Stream 是空的,不会有任何数据输出。

4. 如何使用 async* 生成异步数据流?

async* 用于返回 Stream,可以通过 yield 来逐个发出数据。你也可以结合 await 来进行异步操作后再发出数据。这是一个典型的用法:

Stream<int> generateNumbers() async* {for (int i = 1; i <= 5; i++) {await Future.delayed(Duration(seconds: 1));  // 模拟异步操作yield i;  // 发出数据}
}void main() async {await for (var number in generateNumbers()) {print(number);}
}

输出:

1
2
3
4
5

在这个例子中,async* 通过 yield 发出了多个数字,每次发出时都延迟 1 秒。

总结
  • async*yield 通常一起使用来生成和发出异步数据流。
  • 不一定非要有 yield (但不使用 yield 意义不大),但如果你希望生成一个有数据的流,就需要使用 yield 或其他发出数据的方式(例如 yield*)。
  • 如果你在 async* 中没有 yield,返回的 Stream 将不会发出任何数据,通常这种情况用于创建空流或只执行异步操作的函数。

因此,虽然 async*yield 是紧密相关的,但它们不必总是同时使用。如果不使用 yield,可以生成一个空流或执行异步操作,但不会有数据发出。

相关文章:

Flutter中的Future和Stream

在 Flutter 中&#xff0c;Future 和 Stream 都是用于处理异步操作的类&#xff0c;它们都基于 Dart 的异步编程模型&#xff0c;但是它们的使用场景和工作方式有所不同。以下是它们的区别以及各自适用的场景。 目录 一、Future1、基本使用2、异常处理1. catchError2. onError…...

107.【C语言】数据结构之二叉树求总节点和第K层节点的个数

目录 1.求二叉树总的节点的个数 1.容易想到的方法 代码 缺陷 思考:能否在TreeSize函数内定义静态变量解决size的问题呢? 其他写法 运行结果 2.最好的方法:分而治之 代码 运行结果 2.求二叉树第K层节点的个数 错误代码 运行结果 修正 运行结果 其他写法 1.求二…...

spring boot支持那些开发工具?

Spring Boot 支持多种开发工具&#xff0c;以帮助开发者更高效地进行应用开发。以下是小编给大家分享几种常用的开发工具及其特点&#xff1a; IntelliJ IDEA&#xff1a; IntelliJ IDEA 是一款非常流行的 Java IDE&#xff0c;它提供了对 Spring Boot 的全面支持&#xff0c;…...

Go-MediatR:Go语言中的中介者模式

在Go语言中&#xff0c;确实存在一个与C#中的MediatR类似的组件包&#xff0c;名为Go-MediatR。 Go-MediatR是一个受.NET中MediatR库启发的Go语言实现&#xff0c;它专注于通过中介者模式简化命令查询责任分离&#xff08;CQRS&#xff09;模式的处理和在事件驱动架构中的应用…...

5.11【机器学习】

先是对图像进行划分 划分完后&#xff0c; 顺序读取文件夹&#xff0c;在文件夹里顺序读取图片&#xff0c; 卷积层又称为滤波器&#xff0c;通道是说滤波器的个数&#xff0c;黑白通道数为1&#xff0c;RGB通道个数为3 在输入层&#xff0c;对于输入层而言&#xff0c;滤波…...

在 CentOS 上安装 Docker:构建容器化环境全攻略

一、引言 在当今的软件开发与运维领域&#xff0c;Docker 无疑是一颗璀璨的明星。它以轻量级虚拟化的卓越特性&#xff0c;为应用程序的打包、分发和管理开辟了崭新的高效便捷之路。无论是开发环境的快速搭建&#xff0c;还是生产环境的稳定部署&#xff0c;Docker 都展现出了…...

Python练习(2)

重复元素判定续。利用集合的无重复性来编写一个程序如果有一个元素出现了不止一次则返回true但不要改变原来列表的值&#xff1a; 一&#xff1a; def has_duplicates(lst): # 使用集合来存储已经见过的元素 seen set() for item in lst: if item in seen: # 如果元素已经在…...

如何实现一套键盘鼠标控制两台计算机(罗技Options+ Flow功能快速实现演示)

需求背景 之前我写过一篇文章如何实现一套键盘鼠标控制两台计算机&#xff08;Mouse Without Borders快速上手教程&#xff09;_一套键鼠控制两台电脑-CSDN博客 当我们在局域网内有两台计算机&#xff0c;想使用一套键鼠操控时&#xff0c;可以安装Mouse Without Borders软件…...

现代应用程序中基于 Cell 架构的安全防护之道

在飞速发展的软件开发领域&#xff0c;基于 Cell 的架构日益流行起来。其概念源自船舶舱壁的设计准则&#xff0c;即单独的水密舱室能允许故障孤立存在。通过将这个概念应用于软件&#xff0c;我们创建了一个架构&#xff0c;将应用程序划分为离散的、可管理的组件&#xff0c;…...

【导航查询】.NET开源 ORM 框架 SqlSugar 系列

.NET开源 ORM 框架 SqlSugar 系列 【开篇】.NET开源 ORM 框架 SqlSugar 系列【入门必看】.NET开源 ORM 框架 SqlSugar 系列【实体配置】.NET开源 ORM 框架 SqlSugar 系列【Db First】.NET开源 ORM 框架 SqlSugar 系列【Code First】.NET开源 ORM 框架 SqlSugar 系列【数据事务…...

【基础分析】——Qt 信号和槽的机制 优点

QT信号和槽机制的优点包括&#xff1a; 1、类型安全&#xff1a; 信号和槽的签名必须是等同的&#xff0c;即信号的参数类型和参数个数必须与接收该信号的槽的参数类型和参数个数相同。 2、松散耦合&#xff1a; 信号和槽机制减弱了Qt对象的耦合度。激发信号的Qt对象无须知道…...

Vue3学习宝典

1.ref函数调用的方式生成响应式数据&#xff0c;可以传复杂和简单数据类型 <script setup> // reactive接收一个对象类型的数据 import { reactive } from vue;// ref用函数调用的方式生成响应式数据&#xff0c;可以传复杂和简单数据类型 import { ref } from vue // 简…...

leecode96.不同的二叉搜索树

在画的过程中发现规律&#xff0c;每次选择不同的节点作为根节点&#xff0c;左右两边的节点再排列组合一下就能求出总数 class Solution { public:int numTrees(int n) {vector<int> dp(n1,0);dp[0]1;for(int i1;i<n;i)for(int j0;j<i;j)dp[i]dp[i-j-1]*dp[j];ret…...

树莓派基本配置-基础配置配置

树莓派基本配置 文章目录 树莓派基本配置前言硬件准备树莓派刷机串口方式登录树莓派接入网络ssh方式登录树莓派更换国内源xrdp界面登录树莓派远程文件传输FileZilla 前言 树莓派是一款功能强大且价格实惠的小型计算机&#xff0c;非常适合作为学习编程、物联网项目、家庭自动化…...

手机卡限速丨中国移动5G变3G,网速500kb

以下猜测错误&#xff0c;又有新的猜测&#xff1a;河南移动的卡出省限速。可能是因为流量结算。 “2024年7月1日起&#xff0c;中国移动集团内部将开启跨省流量结算” 在深圳四五年了&#xff0c;之前没有过&#xff0c;就从上个月开始。11月底解除限速&#xff0c;12月刚开…...

SpringCloud之OpenFeign:OpenFeign与Feign谁更适合你的SpringCloud项目?

目录 一、OpenFeign简介1、OpenFeign是什么&#xff08;1&#xff09;核心概念&#xff08;2&#xff09;工作原理&#xff08;3&#xff09;主要特点&#xff08;4&#xff09;使用场景&#xff08;5&#xff09;与Feign的区别&#xff08;6&#xff09;总结 2、OpenFeign与Fe…...

yt6801 ubuntu有线连接驱动安装

耀世16pro的有线网卡驱动安装 下载地址: YT6801 千兆PCIE以太网控制器芯片 1. 创建安装目录 mkdir yt68012. 解压驱动文件 unzip yt6801-linux-driver-1.0.27.zip -d yt68013. 进入驱动目录 cd yt68014. 安装驱动 以 root 权限运行安装脚本&#xff1a; sudo su ./yt_ni…...

算法日记 36-38day 动态规划

今天把动态规划结束掉&#xff0c;包括子序列以及编辑距离 题目&#xff1a;最长公共子序列 1143. 最长公共子序列 - 力扣&#xff08;LeetCode&#xff09; 给定两个字符串 text1 和 text2&#xff0c;返回这两个字符串的最长 公共子序列 的长度。如果不存在 公共子序列 &…...

hdlbits系列verilog解答(Dff16e-同步复位上升沿16位触发器)-85

文章目录 一、问题描述二、verilog源码三、仿真结果一、问题描述 本节学习如何创建16位D触发器。有时仅修改一组触发器一部分是有用的。字节使能控制16位寄存器的哪一个字节应当被修改,其中teena[1]控制高位字节[15:8],teena[0]控制低位字节[7:0]。restn是一个同步低电平有效…...

HTTPTomcatServlet

今日目标: 了解JavaWeb开发的技术栈理解HTTP协议和HTTP请求与响应数据的格式掌握Tomcat的使用掌握在IDEA中使用Tomcat插件理解Servlet的执行流程和生命周期掌握Servlet的使用和相关配置1,Web概述 1.1 Web和JavaWeb的概念 Web是全球广域网,也称为万维网(www),能够通过浏览…...

接口测试中缓存处理策略

在接口测试中&#xff0c;缓存处理策略是一个关键环节&#xff0c;直接影响测试结果的准确性和可靠性。合理的缓存处理策略能够确保测试环境的一致性&#xff0c;避免因缓存数据导致的测试偏差。以下是接口测试中常见的缓存处理策略及其详细说明&#xff1a; 一、缓存处理的核…...

Appium+python自动化(十六)- ADB命令

简介 Android 调试桥(adb)是多种用途的工具&#xff0c;该工具可以帮助你你管理设备或模拟器 的状态。 adb ( Android Debug Bridge)是一个通用命令行工具&#xff0c;其允许您与模拟器实例或连接的 Android 设备进行通信。它可为各种设备操作提供便利&#xff0c;如安装和调试…...

【入坑系列】TiDB 强制索引在不同库下不生效问题

文章目录 背景SQL 优化情况线上SQL运行情况分析怀疑1:执行计划绑定问题?尝试:SHOW WARNINGS 查看警告探索 TiDB 的 USE_INDEX 写法Hint 不生效问题排查解决参考背景 项目中使用 TiDB 数据库,并对 SQL 进行优化了,添加了强制索引。 UAT 环境已经生效,但 PROD 环境强制索…...

【网络安全产品大调研系列】2. 体验漏洞扫描

前言 2023 年漏洞扫描服务市场规模预计为 3.06&#xff08;十亿美元&#xff09;。漏洞扫描服务市场行业预计将从 2024 年的 3.48&#xff08;十亿美元&#xff09;增长到 2032 年的 9.54&#xff08;十亿美元&#xff09;。预测期内漏洞扫描服务市场 CAGR&#xff08;增长率&…...

系统设计 --- MongoDB亿级数据查询优化策略

系统设计 --- MongoDB亿级数据查询分表策略 背景Solution --- 分表 背景 使用audit log实现Audi Trail功能 Audit Trail范围: 六个月数据量: 每秒5-7条audi log&#xff0c;共计7千万 – 1亿条数据需要实现全文检索按照时间倒序因为license问题&#xff0c;不能使用ELK只能使用…...

页面渲染流程与性能优化

页面渲染流程与性能优化详解&#xff08;完整版&#xff09; 一、现代浏览器渲染流程&#xff08;详细说明&#xff09; 1. 构建DOM树 浏览器接收到HTML文档后&#xff0c;会逐步解析并构建DOM&#xff08;Document Object Model&#xff09;树。具体过程如下&#xff1a; (…...

12.找到字符串中所有字母异位词

&#x1f9e0; 题目解析 题目描述&#xff1a; 给定两个字符串 s 和 p&#xff0c;找出 s 中所有 p 的字母异位词的起始索引。 返回的答案以数组形式表示。 字母异位词定义&#xff1a; 若两个字符串包含的字符种类和出现次数完全相同&#xff0c;顺序无所谓&#xff0c;则互为…...

初学 pytest 记录

安装 pip install pytest用例可以是函数也可以是类中的方法 def test_func():print()class TestAdd: # def __init__(self): 在 pytest 中不可以使用__init__方法 # self.cc 12345 pytest.mark.api def test_str(self):res add(1, 2)assert res 12def test_int(self):r…...

云原生玩法三问:构建自定义开发环境

云原生玩法三问&#xff1a;构建自定义开发环境 引言 临时运维一个古董项目&#xff0c;无文档&#xff0c;无环境&#xff0c;无交接人&#xff0c;俗称三无。 运行设备的环境老&#xff0c;本地环境版本高&#xff0c;ssh不过去。正好最近对 腾讯出品的云原生 cnb 感兴趣&…...

MacOS下Homebrew国内镜像加速指南(2025最新国内镜像加速)

macos brew国内镜像加速方法 brew install 加速formula.jws.json下载慢加速 &#x1f37a; 最新版brew安装慢到怀疑人生&#xff1f;别怕&#xff0c;教你轻松起飞&#xff01; 最近Homebrew更新至最新版&#xff0c;每次执行 brew 命令时都会自动从官方地址 https://formulae.…...