Guava限流神器:RateLimiter使用指南

1. 引言

可能有些小伙伴听到“限流”这个词就觉得头大,感觉像是一个既复杂又枯燥的话题。别急,小黑今天就要用轻松易懂的方式,带咱们一探RateLimiter的究竟。

想象一下,当你去超市排队结账时,如果收银台开得越多,排队的人就会越少,速度也就越快。但如果超市为了节省成本,只开了一两个收银台,那排队的速度就会大大降低,甚至造成拥堵。在软件世界里,特别是在处理网络请求或资源访问时,也存在类似的问题。这时候,RateLimiter就像是那个调节收银台开放数量的智能系统,它能帮助我们控制资源的访问速率,防止过载。

2. RateLimiter的基本概念

我们得先弄清楚RateLimiter到底是什么。简单来说,RateLimiter是一个用于控制操作频率的工具。就像你家的水龙头,你可以调节它的开关,控制水流的大小。RateLimiter也一样,它可以控制程序中某个操作的执行频率。

处理网络请求或者数据库操作时,这个工具显得尤为重要。想象一下,如果咱们的服务器接到太多请求,或者数据库同时被大量查询,没有任何限制地处理这些请求,服务器和数据库可能就会因为负载过重而崩溃。这就像是一个突然涌入的人潮,把超市挤得水泄不通。RateLimiter能帮助我们像调节水龙头一样,合理分配处理能力,确保系统的稳定运行。

RateLimiter是怎么工作的呢?它其实是基于令牌桶算法的。简单来说,这个算法就像是一个放有令牌的桶,桶里的令牌按固定速率放入。每次操作(比如一个网络请求)都需要从桶里取走一个令牌。如果桶里没有令牌了,操作就需要等待,直到桶里再次有了令牌。这样,操作的频率就被控制住了。

让咱们来看一个简单的例子,用Java代码实现RateLimiter:

import com.google.common.util.concurrent.RateLimiter;public class RateLimiterDemo {public static void main(String[] args) {// 创建一个每秒放入5个令牌的RateLimiterRateLimiter limiter = RateLimiter.create(5.0);for (int i = 0; i < 10; i++) {// 请求一个令牌limiter.acquire();System.out.println("处理请求: " + i);}}
}

这段代码创建了一个RateLimiter,它每秒产生5个令牌。在一个循环中,我们通过acquire()方法

从RateLimiter获取令牌。如果令牌不够,acquire()会阻塞,直到获取到令牌。

PS: 小黑收集整理了一份超级全面的复习面试资料包,在这偷偷分享给你~
链接:https://sourl.cn/CjagkK 提取码:yqwt

3. Guava RateLimiter的工作原理

现在咱们来深入挖掘一下RateLimiter的内部机制。了解它是如何工作的,不仅能帮助我们更好地使用它,还能让我们在遇到问题时,更有针对性地解决。

令牌桶算法

RateLimiter的核心是一种被称为“令牌桶算法”的东西。想象一个桶,这个桶以固定速率往里面放入小令牌。每次咱们的程序想要执行一个操作(比如发起一个网络请求),就需要从这个桶里取出一个令牌。如果桶空了,意味着令牌用完了,操作就得等一等,直到桶里再次有令牌。这个过程控制了操作的频率,确保了咱们的程序不会因为太“急躁”而崩溃。

平滑速率限制

Guava的RateLimiter不仅仅是简单地实现了令牌桶算法,它还提供了“平滑”速率的限制。平滑限制意味着RateLimiter会尽量平均地分配令牌,而不是突然间就把所有令牌都释放出来。这种方式更加符合实际应用场景,比如处理网络请求时,咱们通常希望请求以相对平稳的速率处理,而不是一会儿很快一会儿很慢。

SmoothBursty与SmoothWarmingUp

RateLimiter提供了两种模式:SmoothBursty和SmoothWarmingUp。

  • SmoothBursty:这种模式适合于突发请求较多的场景。它允许在短时间内处理大量请求,然后速率会逐渐下降到稳定状态。

  • SmoothWarmingUp:这个模式适用于需要预热的场景。它会在启动时逐渐增加发放令牌的速率,直到达到稳定状态。这对于那些刚开始时资源较少但随后需要稳定运行的系统很有用。

让咱们通过一些Java代码来看看这两种模式:

import com.google.common.util.concurrent.RateLimiter;public class RateLimiterModes {public static void main(String[] args) {// SmoothBursty模式RateLimiter burstyLimiter = RateLimiter.create(5.0); // 每秒5个令牌// 这里模拟请求,观察令牌获取情况// SmoothWarmingUp模式RateLimiter warmingUpLimiter = RateLimiter.create(5.0, 1, TimeUnit.SECONDS); // 每秒5个令牌,预热时间1秒// 同样模拟请求,观察令牌获取情况}
}

在这段代码中,小黑创建了两个RateLimiter的实例,分别代表两种不同的模式。可以看到,通过简单的API调用,就能实现复杂的限流逻辑。

理解了RateLimiter的内部机制后,咱们就能更好地理解它为什么能有效地控制操作频率,保证系统的稳定性。同时,了解这些原理也能帮助咱们根据不同的应用场景选择合适的RateLimiter模式。

4. 实际代码示例
基本使用

咱们先来看一个最基础的RateLimiter使用案例。在这个例子中,小黑会创建一个RateLimiter,然后模拟一系列请求,看看RateLimiter是如何控制请求速率的。

import com.google.common.util.concurrent.RateLimiter;public class BasicRateLimiterExample {public static void main(String[] args) {// 创建一个每秒允许2个请求的RateLimiterRateLimiter limiter = RateLimiter.create(2.0);for (int i = 1; i <= 10; i++) {double waitTime = limiter.acquire(); // 请求令牌并获取等待时间System.out.println("处理请求 " + i + ",等待时间: " + waitTime + "秒");}}
}

这段代码中,小黑创建了一个每秒允许两个请求的RateLimiter。通过循环模拟了10个请求,并打印每个请求的等待时间。这个简单的例子能帮助咱们直观地看到RateLimiter如何控制请求的速率。

高级用法

现在,咱们来看一个更高级的用法。在这个例子中,小黑会使用SmoothWarmingUp模式的RateLimiter,这种模式对于需要“预热”过程的场景非常适用。

import com.google.common.util.concurrent.RateLimiter;
import java.util.concurrent.TimeUnit;public class AdvancedRateLimiterExample {public static void main(String[] args) {// 创建一个预热时间为10秒,每秒5个请求的RateLimiterRateLimiter warmingUpLimiter = RateLimiter.create(5.0, 10, TimeUnit.SECONDS);for (int i = 1; i <= 10; i++) {double waitTime = warmingUpLimiter.acquire(); // 请求令牌并获取等待时间System.out.println("处理请求 " + i + ",等待时间: " + waitTime + "秒");}}
}

在这段代码中,RateLimiter的预热时间被设为10秒,意味着它会在这段时间内逐渐增加发放令牌的速率,直到达到每秒5个请求的速度。这个例子展示了RateLimiter在应对需要平滑启动或增加负载的场景时的强大能力。

实际应用场景

让咱们想象一个实际的应用场景。比如说,在一个Web服务中,咱们可能需要控制某些接口的调用频率,以避免服务器过载。这时,RateLimiter就能大显身手了。

import com.google.common.util.concurrent.RateLimiter;
import java.util.stream.IntStream;public class WebServiceRateLimiting {private final RateLimiter rateLimiter = RateLimiter.create(1.0); // 每秒1个请求public void handleRequest(int requestId) {if (rateLimiter.tryAcquire()) {System.out.println("处理请求: " + requestId);// 进行实际的请求处理} else {System.out.println("请求 " + requestId + " 被限流");// 可以返回错误信息或者进行其他操作}}public static void main(String[] args) {WebServiceRateLimiting service = new WebServiceRateLimiting();IntStream.rangeClosed(1, 5).forEach(service::handleRequest);}
}

在这个例子中,小黑创建了一个Web服务的简化模型,其中使用

RateLimiter来控制请求的处理频率。如果请求过于频繁,超出了RateLimiter的限制,那些超出限制的请求就会被拒绝。

5. 高级特性和最佳实践
高级配置

RateLimiter除了基本的创建和使用之外,还提供了一些高级的配置选项,让咱们可以根据具体需求调整其行为。

比如,RateLimiter允许咱们设置超时时间,这在处理不能无限等待的操作时非常有用。看看下面的例子:

import com.google.common.util.concurrent.RateLimiter;public class TimeoutRateLimiterExample {public static void main(String[] args) {RateLimiter limiter = RateLimiter.create(5.0); // 每秒5个令牌// 模拟请求处理for (int i = 0; i < 10; i++) {boolean acquired = limiter.tryAcquire(); // 尝试获取令牌if (acquired) {System.out.println("处理请求: " + i);} else {System.out.println("请求 " + i + " 因超时而放弃");// 处理超时逻辑}}}
}

在这个例子中,小黑使用了tryAcquire()方法而不是acquire()tryAcquire()会立即返回一个布尔值,告诉咱们是否成功获取到了令牌,而不会让程序等待。这对于那些需要快速响应的应用场景非常实用。

最佳实践

使用RateLimiter时,遵循一些最佳实践可以帮助咱们更好地利用其功能,同时避免常见的陷阱。下面是一些小黑总结的要点:

  1. 理解需求:在使用RateLimiter之前,先明确你的应用场景。是需要平滑的限流,还是需要应对突发流量?选择合适的RateLimiter模式对应用的成功至关重要。

  2. 避免过度设计:有时候,简单的限流策略就足够了。不要为了使用RateLimiter而使用RateLimiter。考虑你的实际需求,如果简单的解决方案能工作得很好,就不必复杂化。

  3. 监控和调整:在使用RateLimiter的过程中,监控其表现是很重要的。根据实际运行情况调整RateLimiter的参数,确保它能够适应应用的变化。

  4. 并发考虑:在多线程环境中使用RateLimiter时,要特别注意线程安全和性能问题。正确地管理并发,可以最大限度地发挥RateLimiter的效能。

实践案例

让咱们来看一个实际的案例,展示如何在一个多线程环境中使用RateLimiter。

import com.google.common.util.concurrent.RateLimiter;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.stream.IntStream;public class ConcurrencyRateLimiterExample {private static final RateLimiter rateLimiter = RateLimiter.create(5.0); // 每秒5个请求public static void handleRequest(int requestId) {if (rateLimiter.tryAcquire()) {System.out.println("处理请求: " + requestId);// 进行实际的请求处理} else {System.out.println("请求 " + requestId + " 被限流");// 可以返回错误信息或者进行其他操作}}public static void main(String[] args) {ExecutorService executor = Executors.newFixedThreadPool(10); // 创建一个含有10个线程的线程池IntStream.rangeClosed(1, 20).forEach(i ->executor.submit(() -> handleRequest(i)));executor.shutdown(); // 关闭线程池}
}

在这个例子中,小黑创建了一个线程池来模拟多线程环境,并使用RateLimiter来控制对handleRequest方法的调用频率。这样即使多个线程同时尝试执行操作,RateLimiter也能确保整体的请求速率不会超过设定的限制。

6. RateLimiter与其他Java限流工具的比较

咱们已经探讨了RateLimiter的许多方面,但是在Java的世界里,RateLimiter并不是唯一的限流工具。小黑这次要带大家看看RateLimiter和其他一些流行的Java限流工具的对比,这样咱们在选择合适的工具时就能更有依据。

RateLimiter与Semaphore

Semaphore是Java并发包中的一个工具,它可以限制对某些资源的并发访问。在某些方面,它和RateLimiter有相似之处,但也有明显的区别。

  • Semaphore:它更多的是用于限制同时进行的操作数量,而不是操作的频率。Semaphore允许一定数量的线程同时访问资源。

  • RateLimiter:它主要用于控制操作的速率,保证在给定时间内只允许一定数量的操作发生。

代码示例:Semaphore

让我们看一个简单的Semaphore的使用例子:

import java.util.concurrent.Semaphore;public class SemaphoreExample {private static final Semaphore semaphore = new Semaphore(5); // 同时允许5个线程访问资源public static void handleRequest(int requestId) {try {semaphore.acquire(); // 请求一个许可System.out.println("处理请求: " + requestId);// 进行实际的请求处理} catch (InterruptedException e) {Thread.currentThread().interrupt();} finally {semaphore.release(); // 释放一个许可}}public static void main(String[] args) {for (int i = 0; i < 10; i++) {new Thread(() -> handleRequest(i)).start();}}
}

在这个例子中,Semaphore控制了同时访问资源的线程数量,而不是访问的频率。

RateLimiter与Java 8的Stream API

Java 8的Stream API并不是一个专门的限流工具,但它可以用于处理数据流的速率。通过组合不同的操作,可以实现类似限流的效果。

  • Stream API:主要用于数据流的处理,可以通过其各种操作实现对数据处理速率的控制。

  • RateLimiter:更专注于控制操作的执行频率。

选择合适的工具

选择合适的限流工具时,重要的是要考虑你的具体需求:

  • 如果你需要控制操作的频率,比如API调用或数据库查询的速率,RateLimiter是个不错的选择。
  • 如果你需要控制并发访问资源的数量,Semaphore可能更适合。
  • 对于数据流处理和复杂的数据操作,可以考虑使用Java 8的Stream API。

了解不同工具的优势和适用场景,可以帮助咱们做出更明智的技术决策。每种工具都有它的用武之地,关键在于根据你的应用需求来选择最合适的那一个。

7. 常见问题解答

在小黑之前的章节里,咱们已经探讨了RateLimiter的很多方面,包括它的基本使用、高级特性、以及和其他限流工具的比较。现在,让小黑来帮大家解答一些在使用RateLimiter时可能遇到的常见问题。这些问题基于实际应用场景,希望能帮助咱们更好地理解和使用RateLimiter。

Q1: RateLimiter在分布式系统中如何使用?

在分布式系统中使用RateLimiter时,最大的挑战是如何在多个服务实例间共享限流状态。Guava的RateLimiter是基于单个JVM设计的,它不支持分布式环境。如果你需要在分布式系统中实现限流,可能需要考虑使用像Redis这样的外部存储来维护限流状态,或者使用专门为分布式环境设计的限流工具。

Q2: RateLimiter能否应对突发流量?

RateLimiter的SmoothBursty模式可以应对一定程度的突发流量。它允许在短时间内消耗已经累积的令牌,处理突然增加的请求。但是,如果突发流量超过了RateLimiter的承载能力,超出部分的请求仍然会被限制或延迟处理。

Q3: 使用RateLimiter时,系统的性能会受到影响吗?

使用RateLimiter可能会对系统性能产生一定影响,因为它需要管理和维护令牌的生成与分发。在大多数情况下,这种影响是可接受的,特别是考虑到它带来的系统稳定性。然而,在高性能要求的场景中,建议进行详细的性能测试,以确保RateLimiter的使用不会成为瓶颈。

Q4: RateLimiter适用于哪些场景?

RateLimiter特别适用于需要控制请求速率的场景,如API限流、数据库访问控制等。它也可以用于控制资源的使用频率,比如文件读写、网络通信等。总之,任何需要平滑流量、避免资源过载的场景都可以考虑使用RateLimiter。

Q5: 如何调整RateLimiter的限流策略?

RateLimiter允许动态调整限流策略。你可以使用setRate(double permitsPerSecond)方法来调整每秒允许的请求数量。这在应对动态变化的负载或实现更灵活的限流策略时非常有用。

示例代码:动态调整RateLimiter

下面是一个如何动态调整RateLimiter的例子:

import com.google.common.util.concurrent.RateLimiter;public class DynamicRateLimiterExample {public static void main(String[] args) {RateLimiter limiter = RateLimiter.create(5.0); // 初始每秒5个令牌// 模拟请求处理for (int i = 0; i < 10; i++) {limiter.acquire();System.out.println("处理请求: " + i);if (i == 5) {limiter.setRate(10.0); // 动态调整为每秒10个令牌}}}
}

在这段代码中,小黑开始时设置RateLimiter每秒产生5个令牌。处理了一些请求后,小黑动态地将速率调整为每秒10个令牌,以适应可能的变化需求。

8. 总结
RateLimiter的优点
  1. 灵活性:RateLimiter提供了多种限流策略,满足不同场景的需求,比如SmoothBursty和SmoothWarmingUp模式,以及能够动态调整速率的特性。

  2. 简单易用:Guava的RateLimiter非常容易理解和使用,API设计直观,使得在实际项目中快速实现限流成为可能。

  3. 性能:虽然RateLimiter会带来一定的性能开销,但是在大多数场景下,这种开销是可接受的,特别是考虑到它带来的稳定性和可靠性。

  4. 稳定性:使用RateLimiter可以有效地防止系统过载,提高系统的稳定性和可靠性,特别是在面对高并发和大量请求的场景下。

适用场景

RateLimiter特别适用于以下几种场景:

  1. API限流:在Web服务中控制API的访问频率,防止因过度使用而导致的服务不稳定。

  2. 数据库访问控制:控制对数据库的访问频率,减少数据库压力,避免因查询过多而导致的性能问题。

  3. 资源使用管理:在需要控制对文件、网络等资源的访问频率时,使用RateLimiter可以平滑地管理资源使用。

最后的建议

RateLimiter是一个强大且实用的工具,但是像所有工具一样,关键在于如何使用它。理解你的需求,选择合适的限流策略,合理地集成到你的应用中,这些都是成功使用RateLimiter的关键。

最后,小黑希望这篇文章能帮助大家更好地理解和使用RateLimiter,让咱们的应用更加稳定和高效。


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

如若内容造成侵权/违法违规/事实不符,请联系一条长河网进行投诉反馈,一经查实,立即删除!

相关文章

被复线远传节点机JR-IPAM-1600

产品描述 JR-IPAM-1600J是一款被复线远传节点机&#xff0c;通过传统双绞线电缆&#xff08;被复线\网线\对数电缆\矿用电缆等&#xff09;&#xff0c;用户就可以快速组成一个高速的传输网、局域网。它具有传输速率高、运行稳定、快速安装部署的特点&#xff0c;设备特有的AU…

【React】React 生命周期完全指南

&#x1f308;个人主页: 鑫宝Code &#x1f525;热门专栏: 闲话杂谈&#xff5c; 炫酷HTML | JavaScript基础 ​&#x1f4ab;个人格言: "如无必要&#xff0c;勿增实体" 文章目录 React 生命周期完全指南一、生命周期概述二、生命周期的三个阶段2.1 挂载阶段&a…

自定义springCloudLoadbalancer简述

概述 目前后端用的基本都是springCloud体系&#xff1b; 平时在dev环境开发时&#xff0c;会把自己的本地服务也注册上去&#xff0c;但是这样的话&#xff0c;在客户端调用时请求可能会打到自己本地&#xff0c;对客户端测试不太友好. 思路大致就是前端在请求头传入指定ip&a…

Vue3-子传父

1. 主组件 App.vue&#xff08;父组件&#xff09; 在 App.vue 中&#xff0c;我们先引入了子组件 SonCom&#xff0c;这个小家伙将在父组件中出场。 接着&#xff0c;我们写了一个叫 getMessage 的函数。这个函数的任务很简单——接收子组件传来的消息&#xff0c;然后用 con…

vue--vueCLI

何为CLI ■ CLI是Command-Line Interface,俗称脚手架. ■ 使用Vue.js开发大型应用时&#xff0c;我们需要考虑代码目录结构、项目结构和部署、热加载、代码单元测试等事情。&#xff08;vue 脚手架的作用&#xff09;&#xff0c; 而通过vue-cli即可&#xff1a;vue-cli 可以…

基于 JAVASSM(Java + Spring + Spring MVC + MyBatis)框架开发一个医院挂号系统

基于 JAVASSM&#xff08;Java Spring Spring MVC MyBatis&#xff09;框架开发一个医院挂号系统是一个实用的项目。 步骤一&#xff1a;需求分析 明确系统需要实现的功能&#xff0c;比如&#xff1a; 用户注册和登录查看医生列表预约挂号查看预约记录取消预约管理员管…

Golang--反射

1、概念 反射可以做什么? 反射可以在运行时动态获取变量的各种信息&#xff0c;比如变量的类型&#xff0c;类别等信息如果是结构体变量&#xff0c;还可以获取到结构体本身的信息(包括结构体的字段、方法)通过反射&#xff0c;可以修改变量的值&#xff0c;可以调用关联的方法…

计算机网络 TCP/IP体系 数据链路层

一. 数据链路层的基本概念 数据链路层主要负责节点之间的通信&#xff0c;确保从物理层接收到的数据能够准确无误地传输到网络层。 数据链路层使用的信道主要有以下两种类型: 点对点信道: 这种信道使用一对一的点对点通信方式。广播信道: 这种信道使用一对多的广播通信方式,…

使用注解装配Bean

&#xff01;&#xff01;&#xff01;仅用作学习笔记记录&#xff01;&#xff01;&#xff01; 一、一些概念&#xff1a; 1.定义Bean的注解&#xff1a; 在实际开发中分别使用Repository、Service与Controller对实现类进行标注。 2.注入Bean组件装配的注解 Autowired默认…

csa文件管理账号管理练习

1、查看/etc/passwd文件的第18-20行内容&#xff0c;并将找到的内容存储至/home/passwd文件中&#xff08;head&#xff0c;tail&#xff0c;>,>>&#xff09; # head -num 显示文件头num行 # tail -num &#xff1a;显示文件的最后num行 # 输出重定向 > # 使用…

软考高级架构 - 8.1 - 系统质量属性与架构评估 - 超详细讲解+精简总结

第8章 系统质量属性与架构评估 软件系统属性包括功能属性和质量属性&#xff0c;而软件架构重点关注质量属性。 8.1 软件系统质量属性 8.1.1 概述 软件系统的质量反映了其与需求的一致性&#xff0c;即&#xff1a;软件系统的质量高低取决于它是否能满足用户提出的需求&#…

初见Linux:基础开发工具

前言&#xff1a; 这篇文章我们将讲述Linux的基本开发工具&#xff0c;以及讨论Linux的生态圈&#xff0c;最后再了解vim开发工具。 Yum&#xff1a; YUM&#xff08;Yellowdog Updater Modified&#xff09;是一个在Linux系统中用于管理软件包的工具&#xff0c;特别是在基于…

电信基站智能计量新方案:DJSF1352双通讯直流计量电表——安科瑞 丁佳雯

随着信息技术的飞速发展和5G时代的到来&#xff0c;电信基站作为信息传输的重要基础设施&#xff0c;其能耗管理和运营效率成为各大运营商关注的焦点。为了应对日益增长的能耗需求和复杂的运维挑战&#xff0c;采用高效、智能的计量方案显得尤为重要。在这样的背景下&#xff0…

Pytorch cuda版本选择(高效简洁版)

简而言之 Pytorch cuda版本选择 只需要低于cuda驱动版本即可&#xff0c;cuda驱动版本查看命令是nvidia-smi, nvcc -V 是runtimeapi版本可以不用管 1.只要看cuda驱动版本 安装pytorch 选择cuda版本&#xff0c;只要看你电脑cuda驱动版本即可。 2.选择依据 pytorch中cuda版本只…

全网最详细的项目管理完整方案!破解项目管理难题,解决方案一网打尽!

在现代企业中&#xff0c;项目管理愈发复杂&#xff0c;尤其是项目规模扩大、团队多元化的情况下&#xff0c;项目管理的难度逐渐上升。当前&#xff0c;企业在项目管理中面临以下主要问题&#xff1a; 信息碎片化&#xff1a;项目数据和文件分散在不同部门和系统中&#xff0…

数据库的使用05:不规范的写法与操作记录

一、写SQL带数据库名 【严禁】sql写成 select * from databasename.dbo.tablename 【原因】生产环境的databsename不一定和开发环境的databsename一样 【正确写法】select * from tablename 二、不合理的表设计 【改善方法】C#小结&#xff1a;数据库中数据表的设计原则、技…

YOLO11改进 | 融合改进 | C3k2引入多尺度分支来增强特征表征【全网独家 附结构图】

秋招面试专栏推荐 &#xff1a;深度学习算法工程师面试问题总结【百面算法工程师】——点击即可跳转 &#x1f4a1;&#x1f4a1;&#x1f4a1;本专栏所有程序均经过测试&#xff0c;可成功执行&#x1f4a1;&#x1f4a1;&#x1f4a1; 本文给大家带来的教程是将YOLO11的C3k2替…

三维测量与建模笔记 - 3.1 相机标定基本概念

成像领域有多个标定概念 笔记所说的相机标定主要是指几何标定。 相机几何模型基于小孔成像原理&#xff0c;相关文章很多&#xff0c;上图中R t矩阵是外参矩阵&#xff08;和相机在世界空间中的位姿相关&#xff09;&#xff0c;K矩阵是内参矩阵&#xff08;和相机本身参数相关…

安卓/华为手机恢复出厂设置后如何恢复照片

绝大多数安卓用户都会经历过手机恢复出厂设置&#xff0c;部分用户可能没有意识到手机恢复出厂设置可能会导致数据丢失。但是&#xff0c;当您在 云盘上进行备份或在设备上进行本地备份时&#xff0c;情况就会有所不同&#xff0c;并且当您将 安卓手机恢复出厂设置时&#xff0…

丹摩征文活动 |【AI落地应用实战】文本生成语音Parler-TTS + DAMODEL复现指南

目录 一、Parler-TTS简介1.1、TTS 模型1.2、Parler-TTS 二、Parler-TTS复现流程2.1、创建实例2.2、配置代码与环境2.3、配置预训练模型2.4、Parles-TTS使用 Parler-TTS 是一个由 Hugging Face 开源的文本生成语音 (Text-to-Speech, TTS) 模型。它的设计目的是生成高质量的语音输…