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

深入浅出WebRTC—ALR

ALR(Application Limited Region)指的是网络传输过程中,由于应用层的限制(而非网络拥塞)导致带宽未被充分利用的情况。在这种情况下,应用层可能因为处理能力、手动配置或其他因素无法充分利用可用带宽,导致实际传输速率低于网络最大可能提供的速率。因此,在进行拥塞控制或带宽估算时,识别和处理 ALR 状态对于避免不必要的码率下调或误判网络状况至关重要。

1. 配置

ALR逻辑比较简单,配置项就3个,主要用来协助定义进入和退出ALR状态的规则。

struct AlrDetectorConfig {// ALR使用的带宽是估计带宽乘以一个比例系数double bandwidth_usage_ratio = 0.65;// 带宽使用从高点下降,且剩余可用带宽占总容量的比例达到或超过此值时,视为开始进入ALR状态。double start_budget_level_ratio = 0.80;// 当带宽使用回升,且实际使用比例再次超过此值时,认为已从ALR状态中恢复出来。double stop_budget_level_ratio = 0.50;std::unique_ptr<StructParametersParser> Parser();
};

2. 静态结构

ALR实现只有两个类,AlrDetector提供接口,其内部使用IntervalBudget来更新ALR状态,对外接口只有三个:

1)OnBytesSent:每发送完一个报文需要调用此接口,此接口完成Budget水位的更新。

2)SetEstimatedBitrate:设置估计带宽,估计带宽会影响Budget水位调整的细节。

3)GetApplicationLimitedRegionStartTime:如果有值,表示进入ALR状态,否则表示退出ALR状态。这里为什么不用一个bool值来表示是否处于ALR状态,是因为某些逻辑需要知道是什么时候进入ALR状态和什么时候退出ALR状态的。

3. 调用流程

ALR处理逻辑主要涉及两个调用链,一个是发送报文后,调用AlrDetector::OnBytesSent更新Budget水位,通过Budget水位才能判断当前ALR状态;另一个是带宽评估变化调用AlrDetector::SetEstimatedBitrate设置估计带宽,估计带宽会影响水位更新细节和ALR状态判断规则。

4. 实现

4.1. Bucket模型

为了便于理解WebRTC是如何判断ALR状态,引入一个Bucket模型。Bucket中的水位表示当前Budget,可以认为是账户余额,IncreateBudget会向账户中存入资金,增加账户余额,从而提高Bucket中的水位;UseBudget会从账户中支取资金,减少账户余额,从而降低Bucket中的水位。

IntervalBudget是Bucket模型的实现者,只是Budget从金钱换成了数据,每过一段时间 t 计算应该发送的数据:估计带宽 * t,这些数据会存入Budget,每次发送完报文,需要消耗报文对应数据量的Budget。

相关逻辑代码如下:

void AlrDetector::OnBytesSent(size_t bytes_sent, int64_t send_time_ms) {...int64_t delta_time_ms = send_time_ms - *last_send_time_ms_;last_send_time_ms_ = send_time_ms;// 减少Budgetalr_budget_.UseBudget(bytes_sent);// 增加Budgetalr_budget_.IncreaseBudget(delta_time_ms);...
}

通过定义桶的高度,并在桶上面画上80%和50%两个刻度,bytes_remaining_为当前Budget水位,从而形成了一个完整的Bucket模型,如下图所示,图中变量与代码中变量一一对应。

其中桶高度max_bytes_in_budget_定义如下:

void IntervalBudget::set_target_rate_kbps(int target_rate_kbps) {// 更新目标速率target_rate_kbps_ = target_rate_kbps;// 计算时间窗口内最多可以发送多少数据,kWindowMs = 500max_bytes_in_budget_ = (kWindowMs * target_rate_kbps_) / 8;...
}

4.2. 估计带宽

从上面的Bucket模型可知,估计带宽会影响到桶的高度和Budget流入的速度。外部会向AlrDectector实时更新估计带宽,但AlrDetector不会全部使用,而是乘以一个系数0.65(这看起来像是一个经验值)再设置到IntervalBudget。

void AlrDetector::SetEstimatedBitrate(int bitrate_bps) {RTC_DCHECK(bitrate_bps);int target_rate_kbps =static_cast<double>(bitrate_bps) * conf_.bandwidth_usage_ratio / 1000;alr_budget_.set_target_rate_kbps(target_rate_kbps);
}

4.3. 水位变化

Bucket中的水位用bytes_remaining_表示,80%和50%两条水位线将桶的水位位置划分为三个区:A、B、C,则水位的变化可以穷举为:A -> B、A -> C、B -> A、B -> C、C -> A、C -> B六种情况。

WebRTC实现定义如果水位处于A区,则一定是“进入ALR”状态,因为实际发送数据远少于应该发送数据;如果水位处于C区,则一定是“退出ALR”状态,因为实际发送数据已经大于应该发送数据。B区是一个过渡区,它的ALR状态和上一个水位相关,下面我们看下水位在A、B和C三个区中动态变化中,ALR状态的变化。

4.3.1. A -> B

刚开始处于“进入ALR”状态,bytes_remaining_比例从高于80%,下降到低于80%但高于50%,ALR状态保持不变。

4.3.2. A -> C

刚开始处于“进入ALR”状态,bytes_remaining_比例从高于80%,下降到低于50%,变为“退出ALR”状态。

4.3.3. B -> A

刚开始可能处于“进入ALR”状态也可能处于“退出ALR”状态,bytes_remaining_从低于80%但高于50%变为高于80%。

1)如果刚开始处于“进入ALR”状态(从A区进入B区),则状态保持不变,仍为“进入ALR”状态;

2)如果刚开始处于“退出ALR”状态(从C区进入B区),则变为“进入ALR”状态。

总之,不管之前是什么状态,进入A区后肯定是“进入ALR”状态。

4.3.4. B -> C

刚开始可能处于“进入ALR”状态也可能处于“退出ALR”状态,bytes_remaining_从低于80%但高于50%变为低于50%。

1)如果刚开始处于“进入ALR”状态(从A区进入B区),则状态变为“退出ALR”状态;

2)如果刚开始处于“退出ALR”状态(从C区进入B区),则状态保持不变,仍为“退出ALR”状态。

总之,不管之前是什么状态,进入C区后肯定是“退出ALR”状态。

4.3.5. C -> A

刚开始处于“退出ALR”状态,bytes_remaining_从低于50%变为高于80%,变为“进入ALR”状态。

4.3.6. C -> B

刚开始处于“退出ALR”状态,bytes_remaining_从低于50%变为高于50%但低于80%,状态保持不变。

4.4. 状态机

以上ALR状态跟随水位变化可以用状态机表示如下:

对应源码为:

void AlrDetector::OnBytesSent(size_t bytes_sent, int64_t send_time_ms) {...if (alr_budget_.budget_ratio() > conf_.start_budget_level_ratio && !alr_started_time_ms_) {// 进入ALRalr_started_time_ms_.emplace(rtc::TimeMillis());state_changed = true;} else if (alr_budget_.budget_ratio() < conf_.stop_budget_level_ratio &&alr_started_time_ms_) {// 退出ALRstate_changed = true;alr_started_time_ms_.reset();}...
}

5. ALR应用

5.1. ProbeController

进入ALR状态后,真实发送的码率可能会远低于链路真实容量,如果长时间处于ALR状态而不进行带宽探测,持续的ACK反馈码率会影响最终估计码率,从而导致无法估计带宽失真。因此,专门设置了一个ALR带宽探测机制,进入ALR状态后,ProbeController会立即启动一个ALR带宽探测。

1)GoogCcNetworkController在OnProcessInterval中更新ALR开始时间

NetworkControlUpdate GoogCcNetworkController::OnProcessInterval(ProcessInterval msg) {...// 获取ALR状态absl::optional<int64_t> start_time_ms =alr_detector_->GetApplicationLimitedRegionStartTime();// 设置ALR状态probe_controller_->SetAlrStartTimeMs(start_time_ms);...
}

2)在OnTransportPacketsFeedback中更新ALR结束时间

NetworkControlUpdate GoogCcNetworkController::OnTransportPacketsFeedback(TransportPacketsFeedback report) {...// 获取ALR状态absl::optional<int64_t> alr_start_time =alr_detector_->GetApplicationLimitedRegionStartTime();// 退出ALR状态if (previously_in_alr_ && !alr_start_time.has_value()) {int64_t now_ms = report.feedback_time.ms();acknowledged_bitrate_estimator_->SetAlrEndedTime(report.feedback_time);probe_controller_->SetAlrEndedTimeMs(now_ms);}...
}

3)ProbeController会定时检测ALR状态,适时启动ALR带宽探测,探测码率是当前评估码率的2倍,带宽探测结果在带宽探测机制中获得。

std::vector<ProbeClusterConfig> ProbeController::Process(Timestamp at_time) {...// 以两倍估算带宽进行探测:alr_probe_scale("alr_scale", 2)if (TimeForAlrProbe(at_time) || TimeForNetworkStateProbe(at_time)) {return InitiateProbing(at_time, {estimated_bitrate_ * config_.alr_probe_scale}, true);}...
}

5.2. AcknowledgedBitrateEstimator

ACK码率估计器使用贝叶斯估计算法,其中很重要的一个参数就是数据样本的不确定性,应用如果进入ALR状态,则说明此时真实发送的码率低于链路容量,当前ACK样本不能真实反映链路带宽,则应该适当增加当前数据样本的不确定性,使得带宽评估值更加真实可靠。

1)GoogCcNetworkController在OnSentPacket中设置ALR状态

NetworkControlUpdate GoogCcNetworkController::OnSentPacket(SentPacket sent_packet) {alr_detector_->OnBytesSent(sent_packet.size.bytes(), sent_packet.send_time.ms());acknowledged_bitrate_estimator_->SetAlr(alr_detector_->GetApplicationLimitedRegionStartTime().has_value());...
}

2)在OnTransportPacketsFeedback中更新ALR结束时间

NetworkControlUpdate GoogCcNetworkController::OnTransportPacketsFeedback(TransportPacketsFeedback report) {...// 获取ALR状态absl::optional<int64_t> alr_start_time =alr_detector_->GetApplicationLimitedRegionStartTime();// 退出ALR状态if (previously_in_alr_ && !alr_start_time.has_value()) {int64_t now_ms = report.feedback_time.ms();acknowledged_bitrate_estimator_->SetAlrEndedTime(report.feedback_time);probe_controller_->SetAlrEndedTimeMs(now_ms);}...
}

3)ALR刚结束,码率增速会比正常快,增加贝叶斯估计器历史数据的方差,也就是历史数据的贡献变小,能够更快速响应码率变化。

void AcknowledgedBitrateEstimator::IncomingPacketFeedbackVector(const std::vector<PacketResult>& packet_feedback_vector) {...for (const auto& packet : packet_feedback_vector) {// ALR刚结束,设置码率估计器快速响应新的码率if (alr_ended_time_ && packet.sent_packet.send_time > *alr_ended_time_) {bitrate_estimator_->ExpectFastRateChange();alr_ended_time_.reset();}...}
}

4)贝叶斯估计器在更新数据时,如果当前正处于ALR状态,会为数据样本赋予一个更大的不确定性,使得其在整体数据中的贡献占比降低。

void BitrateEstimator::Update(Timestamp at_time, DataSize amount, bool in_alr) {...float scale = uncertainty_scale_;if (is_small_sample && bitrate_sample_kbps < bitrate_estimate_kbps_) {scale = small_sample_uncertainty_scale_;} else if (in_alr && bitrate_sample_kbps < bitrate_estimate_kbps_) {// Optionally use higher uncertainty for samples obtained during ALR.scale = uncertainty_scale_in_alr_;}...
}

5.3. DelayBasedBWE

由于在 ALR 状态下获取的反馈不是链路满载下的反馈,基于这种反馈向上调整带宽估计值很可能是不准确的,因此,ALR 状态保持原来的估计值,是比较明智的。

void AimdRateControl::ChangeBitrate(const RateControlInput& input, Timestamp at_time) {absl::optional<DataRate> new_bitrate;...switch (rate_control_state_) {case RateControlState::kRcHold:break;case RateControlState::kRcIncrease: {// ALR状态不允许升速if (send_side_ && in_alr_ && no_bitrate_increase_in_alr_) {increase_limit = current_bitrate_;}...}...
}

5.4. LossBasedBweV2

基于丢包的带宽估计器,在全局搜索最优带宽和固有丢包率组合时,需要先构造候选带宽。如果当前正处于 ALR 状态,ACK 码率不能反映网络真实带宽,不应该将 ACK 码率作为候选带宽(可配置)。

std::vector<LossBasedBweV2::ChannelParameters> LossBasedBweV2::GetCandidates(bool in_alr) const {...// 添加一个基于 ACK 码率但进行了回退因子调整的候选带宽if (acknowledged_bitrate_.has_value() &&config_->append_acknowledged_rate_candidate) {if (!(config_->not_use_acked_rate_in_alr && in_alr) ||(config_->padding_duration > TimeDelta::Zero() &&last_padding_info_.padding_timestamp + config_->padding_duration >=last_send_time_most_recent_observation_)) {bandwidths.push_back(*acknowledged_bitrate_ *config_->bandwidth_backoff_lower_bound_factor);}}...
}

6. 总结

识别 ALR 状态对 WebRTC 的拥塞控制来说非常重要,很多人可能没有意识到这一点。为什么这么说,是因为,WebRTC 的拥塞控制算法本质上是一种“刀尖上跳舞”的算法,只有当你要求的最大带宽超过链路容量时,才需要做拥塞控制,此时 WebRTC 会在链路容量的上限疯狂试探。如果带宽随便你使用,怎么用都用不完,怎么用都不会造成拥塞,那也就没必要做拥塞控制了。

ALR 状态本质上是用来标识当前带宽是否够用,进入 ALR 状态和退出 ALR 状态,所需要的控制策略是不一样的,相关算法都需要做调整。ALR 状态就像一个全局开关,开和关直接控制着拥塞控制的行为。

相关文章:

深入浅出WebRTC—ALR

ALR&#xff08;Application Limited Region&#xff09;指的是网络传输过程中&#xff0c;由于应用层的限制&#xff08;而非网络拥塞&#xff09;导致带宽未被充分利用的情况。在这种情况下&#xff0c;应用层可能因为处理能力、手动配置或其他因素无法充分利用可用带宽&…...

BSV区块链技术现实应用原理解析

BSV区块链以其卓越的可扩展性、坚如磐石的安全性、极低的交易成本等特性&#xff0c;成为满足企业当下需求并为企业未来成功奠基铺路的理想技术。 BSV协会近期发布了一个题为《驾驭数字化转型&#xff1a;在自动化世界中建立信任——区块链在数据保护和交易优化中的角色》的报…...

七大基于比较的排序算法

目录 一、基于比较的排序算法概述 1. 插入排序&#xff08;Insertion Sort&#xff09; 2. 选择排序&#xff08;Selection Sort&#xff09; 3. 冒泡排序&#xff08;Bubble Sort&#xff09; 4. 归并排序&#xff08;Merge Sort&#xff09; 5. 快速排序&#xff08;Qu…...

web前端 React 框架面试200题(四)

面试题 97. React 两种路由模式的区别&#xff1f;hash和history&#xff1f; 参考回答&#xff1a; 1: hash路由 hash模式是通过改变锚点(#)来更新页面URL&#xff0c;并不会触发页面重新加载&#xff0c;我们可以通过window.onhashchange监听到hash的改变&#xff0c;从而处…...

5.Fabric的共识机制

在Fabric中,有以下3中典型共识机制。 Solo共识 solo共识机制只能用于单节点模式,即只能有一个Orderer节点,因此,其共识过程很简单,每接收到一个交易信息,就在共识模块的控制下产生区块并广播给节点存储到账本中。 Solo 模式下的共识只适用于一个Orderer节点,所以可以在…...

【safari】react在safari浏览器中,遇到异步时间差的问题,导致状态没有及时更新到state,引起传参错误。如何解决

在safari浏览器中&#xff0c;可能会遇到异步时间差的问题&#xff0c;导致状态没有及时更新到state&#xff0c;引起传参错误。 PS&#xff1a;由于useState是一个普通的函数&#xff0c; 定义为() > void;因此此处不能用await/async替代setTimeout&#xff0c;只能用在返…...

京准:GPS北斗卫星授时信号安全隔离防护装置

京准&#xff1a;GPS北斗卫星授时信号安全隔离防护装置 京准&#xff1a;GPS北斗卫星授时信号安全隔离防护装置 1、主要特点 ★信号加固功能&#xff1a; GPS/BDS单系统信号拒止情况下&#xff08;包含受到GPS L1欺骗干扰、GPS L1压制干扰、BDS B1欺骗干扰、BDS B1压制干扰&…...

解决方案架构师系列 - AWS - Pinpoint

AWS Pinpoint介绍 Amazon Pinpoint 为营销人员和开发人员提供了一款可自定义的工具&#xff0c;助力他们大规模地开展跨渠道、行业和活动的客户通信。 Amazon Pinpoint是一个全面的客户参与平台&#xff0c;‌旨在帮助营销人员和开发人员大规模地开展跨渠道、‌行业和活动的客…...

MF173:将多个工作表转换成PDF文件

我给VBA的定义&#xff1a;VBA是个人小型自动化处理的有效工具。利用好了&#xff0c;可以大大提高自己的工作效率&#xff0c;而且可以提高数据的准确度。“VBA语言専攻”提供的教程一共九套&#xff0c;分为初级、中级、高级三大部分&#xff0c;教程是对VBA的系统讲解&#…...

Docker、containerd、CRI-O 和 runc 之间的区别

容器与 Docker 这个名称并不紧密相关。你可以使用其他工具来运行容器 您可以使用 Docker 或一堆非Docker 的其他工具来运行容器。docker只是众多选项之一&#xff0c;Docker&#xff08;公司&#xff09;在生态系统中创建了一些很棒的工具&#xff0c;但不是全部。 容器方面有…...

PRISM-Python 中的规则一个简单的 Python 规则感应系统

欢迎来到雲闪世界.PRISM 是一种现有算法&#xff08;尽管我确实创建了一个 Python 实现&#xff09;&#xff0c;PRISM 相对简单&#xff0c;但在机器学习中&#xff0c;有时最复杂的解决方案效果最好&#xff0c;有时最简单的解决方案效果最好。然而&#xff0c;当我们希望建立…...

DB-GPT:LLM应用的集大成者

整体架构 架构解读 可以看到&#xff0c;DB-GPT把架构抽象为7层&#xff0c;自下而上分别为&#xff1a; 运行环境&#xff1a;支持本地/云端&单机/分布式等部署方式。顺便一提&#xff0c;RAY是蚂蚁深度参与的一个开源项目&#xff0c;所以对RAY功能的支持应该非常完善。…...

汉明权重(Hamming Weight)(统计数据中1的个数)VP-SWAR算法

汉明权重&#xff08;Hamming Weight&#xff09;&#xff08;统计数据中1的个数&#xff09;VP-SWAR算法 定义 汉明重量是一串符号中非零符号的个数。它等于同样长度的全零符号串的汉明距离(在信息论中&#xff0c;两个等长字符串之间的汉明距离等于两个字符串对应位置的不同…...

基于 PyTorch 的模型瘦身三部曲:量化、剪枝和蒸馏,让模型更短小精悍!

基于 PyTorch 的模型量化、剪枝和蒸馏 1. 模型量化1.1 原理介绍1.2 PyTorch 实现 2. 模型剪枝2.1 原理介绍2.2 PyTorch 实现 3. 模型蒸馏3.1 原理介绍3.2 PyTorch 实现 参考文献 1. 模型量化 1.1 原理介绍 模型量化是将模型参数从高精度&#xff08;通常是 float32&#xff0…...

二、原型模式

文章目录 1 基本介绍2 实现方式深浅拷贝目标2.1 使用 Object 的 clone() 方法2.1.1 代码2.1.2 特性2.1.3 实现深拷贝 2.2 在 clone() 方法中使用序列化2.2.1 代码 2.2.2 特性 3 实现的要点4 Spring 中的原型模式5 原型模式的类图及角色5.1 类图5.1.1 不限制语言5.1.2 在 Java 中…...

【目标检测】Anaconda+PyTorch(GPU)+PyCharm(Yolo5)配置

前言 本文主要介绍在windows系统上的Anaconda、PyTorch、PyCharm、Yolov5关键步骤安装&#xff0c;为使用yolo所需的环境配置完善。同时也算是记录下我的配置流程&#xff0c;为以后用到的时候能笔记查阅。 Anaconda 软件安装 Anaconda官网&#xff1a;https://www.anaconda…...

Django实战项目之进销存数据分析报表——第二天:项目创建和 PyCharm 配置

在上一篇博客中&#xff0c;我们讨论了如何搭建一个全栈 Web 应用的开发环境&#xff0c;包括 Python 环境的创建、Django 和 MySQL 的安装以及前端技术栈的选择。现在&#xff0c;让我们继续深入&#xff0c;学习如何在 PyCharm 中创建一个新的 Django 项目并进行配置。 一…...

静态路由实验

1.实验拓扑图 二、实验要求 1.R6为ISP&#xff0c;接口IP地址均为公有地址&#xff0c;该设备只能配置IP地址&#xff0c;之后不能再对其进行任何配置&#xff1b; 2.R1-R5为局域网&#xff0c;私有IP地址192.168.1.0/24&#xff0c;请合理分配&#xff1b; 3.R1、R2、R4&…...

VSCode STM32嵌入式开发插件记录

要卸载之前搭建的VSCode嵌入式开发环境了&#xff0c;记录一下用的插件。 1.Cortex-Debug https://github.com/Marus/cortex-debug 2.Embedded IDE https://github.com/github0null/eide 3.Keil uVision Assistant https://github.com/jacksonjim/keil-assistant/ 4.RTO…...

linux cpu 占用超100% 分析。

感谢: https://www.cnblogs.com/wolfstark/p/16450131.html 总结&#xff1a; 查看进程中各个线程占用百分比 top -H -p <pid> 某线程100%了 说明 任务处理不过来 会卡 但是永远不可能超100% 系统监视器里面看到的是 所有线程占用的 总和会超100%。 所以最好的情况是&…...

自然学习法和科学学习法

一、自然学习法 自然学习法&#xff1a;什么事自然学习法&#xff0c;特意让kimi来回答了一下。所谓的自然学习法说的俗一点就是野路子学习方法。这种学习方法的特点是“慢”“没有系统性”&#xff0c;学完之后感觉都会了&#xff0c;但是又感觉什么都不会。 二、科学学习法 …...

力扣第二十四题——两两交换链表中的节点

内容介绍 给你一个链表&#xff0c;两两交换其中相邻的节点&#xff0c;并返回交换后链表的头节点。你必须在不修改节点内部的值的情况下完成本题&#xff08;即&#xff0c;只能进行节点交换&#xff09;。 示例 1&#xff1a; 输入&#xff1a;head [1,2,3,4] 输出&#xff…...

C语言柔性数组详解

目录 1.柔性数组 2.柔性数组的特点 3.柔性数组的使用 4.柔性数组的优势 1.柔性数组 C99 中&#xff0c;结构体中的最后一个元素允许是未知大小的数组&#xff0c;这就叫做『柔性数组』成员。 例如&#xff1a; struct S {char c;int n;int arr[];//柔性数组 }; struct …...

自动驾驶---视觉Transformer的应用

1 背景 在过去的几年&#xff0c;随着自动驾驶技术的不断发展&#xff0c;神经网络逐渐进入人们的视野。Transformer的应用也越来越广泛&#xff0c;逐步走向自动驾驶技术的前沿。笔者也在博客《人工智能---什么是Transformer?》中大概介绍了Transformer的一些内容&#xff1a…...

预训练语言模型实践笔记

Roberta output_hidden_statesTrue和last_hidden_states和pooler_output 在使用像BERT或RoBERTa这样的transformer模型时&#xff0c;output_hidden_states和last_hidden_state是两个不同的概念。 output_hidden_states: 这是一个布尔值&#xff0c;决定了模型是否应该返回所…...

Perl 哈希

Perl 哈希 Perl 哈希是一种强大的数据结构&#xff0c;用于存储键值对集合。它是 Perl 语言的核心特性之一&#xff0c;广泛应用于各种编程任务中。本文将详细介绍 Perl 哈希的概念、用法和最佳实践。 什么是 Perl 哈希&#xff1f; Perl 哈希是一种关联数组&#xff0c;其中…...

Linux之Mysql索引和优化

一、MySQL 索引 索引作为一种数据结构,其用途是用于提升数据的检索效率。 1、索引分类 - 普通索引(INDEX):索引列值可重复 - 唯一索引(UNIQUE):索引列值必须唯一,可以为NULL - 主键索引(PRIMARY KEY):索引列值必须唯一,不能为NULL,一个表只能有一个主键索引 - 全…...

springboot业务逻辑写在controller层吗

Spring Boot中的业务逻辑不应该直接写在Controller层。‌ 在Spring Boot项目中&#xff0c;‌通常将业务逻辑分为几个层次&#xff0c;‌包括Controller层、‌Service层、‌Mapper层和Entity层。‌ 1.其中&#xff0c;‌Controller层主要负责处理HTTP请求&#xff0c;‌通过注…...

Ubuntu 24.04 LTS 桌面安装MT4或MT5 (MetaTrader)教程

运行脚本即可在 Ubuntu 24.04 LTS Noble Linux 上轻松安装 MetaTrader 5 或 4 应用程序&#xff0c;使用 WineHQ 进行外汇交易。 MetaTrader 4 (MT4) 或 MetaTrader 5 是用于交易外汇对和商品的流行平台。它支持各种外汇经纪商、内置价格分析工具以及通过专家顾问 (EA) 进行自…...

Go基础编程 - 12 -流程控制

流程控制 1. 条件语句1.1. if...else 语句1.2. switch 语句1.3. select 语句1.3.1. select 语句的通信表达式1.3.2. select 的基特性1.3.3. select 的实现原理1.3.4. 经典用法1.3.4.1 超时控制1.3.4.2 多任务并发控制1.3.4.3 监听多通道消息1.3.4.4 default 实现非堵塞读写 2. …...

汽车信息安全--TLS,OpenSSL

目录 TLS相关知识 加密技术 对称加密 非对称加密 数字签名和CA 信任链 根身份证和自签名 双方TLS认证 加密和解密的性能 TLS相关知识 加密技术 TLS依赖两种加密技术 1. 对称加密&#xff08;symmetric encryption&#xff09; 2. 非对称加密&#xff08;asymmetri…...

深入探索 SQL 中的 LIKE 右模糊匹配(LIKE RIGHT)与左模糊匹配(LIKE LEFT)

引言 在数据库操作中&#xff0c;LIKE 子句是执行模糊搜索的强大工具&#xff0c;用于匹配列中的数据与指定的模式。本文将详细介绍 LIKE 子句中的两种常用模式&#xff1a;右模糊匹配&#xff08;LIKE RIGHT&#xff09;和左模糊匹配&#xff08;LIKE LEFT&#xff09;&#…...

mybatis 多数据源 TDataSource required a single bean, but 2 were found

情况说明&#xff1a; 项目中本来就有一个数据源了&#xff0c;运行的好好的后来又合并了另一个项目&#xff0c;另一个项目也配置了数据源。 于是出现了如下错误&#xff1a; mybatis 多数据源 TDataSource required a single bean, but 2 were found 解决方法&#xff1a…...

Dubbo SPI 之路由器

1. 背景介绍 Dubbo 是一个高性能的 Java RPC 框架&#xff0c;由阿里巴巴开源并广泛应用于分布式系统中。在 Dubbo 的架构中&#xff0c;SPI&#xff08;Service Provider Interface&#xff09;是一个关键组件&#xff0c;允许在运行时动态加载不同的服务实现。SPI 机制提供了…...

Python深度学习环境配置(Pytorch、CUDA、cuDNN),包括Anaconda搭配Pycharm的环境搭建以及基础使用教程(保姆级教程,适合小白、深度学习零基础入门)

全流程导览 一、前言二、基本介绍2.1全过程软件基本介绍2.1.1 Pytorch2.1.2 Anaconda2.1.3 Pycharm2.1.4 显卡GPU及其相关概念2.1.5 CUDA和cuDNN 2.2 各部分相互间的联系和安装逻辑关系 三、Anaconda安装3.1安装Anaconda3.2配置环境变量3.3检验是否安装成功 四、Pycharm安装五、…...

月影护眼大路灯怎么样?书客|月影|霍尼韦尔超硬核实力性能测评pk!

月影护眼大路灯怎么样&#xff1f;选到专业优质的护眼大路灯是真的可以使我们在用眼时减少疲劳感&#xff0c;达到护眼效果&#xff0c;但如果不慎买到劣质的护眼灯产品&#xff0c;不仅达不到健康的环境光&#xff0c;还越用越觉得眼睛疲劳感加重&#xff0c;在水深的护眼灯市…...

邮件安全篇:邮件传输加密(SSL/TLS or STATRTTLS)

1. 前言 使用过邮件客户端的同学一定见过下面这张图。这是客户端账号配置界面&#xff0c;里面有SSL、STARTTLS选项。刚接触邮件客户端的同学肯定会有这些疑问&#xff1a;什么是SSL&#xff1f;什么是STARTTLS&#xff1f;两者有什么区别&#xff1f;具体该如何选择呢&#x…...

【系统架构设计 每日一问】三 Redis支持事务么,Redis的事务如何保证

实际上&#xff0c;关于Redis事务的说法“Redis 的事务只能保证隔离性和一致性&#xff08;I 和 C&#xff09;&#xff0c;无法保证原子性和持久性&#xff08;A 和 D&#xff09;”并不完全准确。下面我将分别解释Redis事务的四个特性&#xff1a;原子性&#xff08;Atomicit…...

【中项】系统集成项目管理工程师-第4章 信息系统架构-4.3应用架构

前言&#xff1a;系统集成项目管理工程师专业&#xff0c;现分享一些教材知识点。觉得文章还不错的喜欢点赞收藏的同时帮忙点点关注。 软考同样是国家人社部和工信部组织的国家级考试&#xff0c;全称为“全国计算机与软件专业技术资格&#xff08;水平&#xff09;考试”&…...

DasViewer打开Revit输出的fbx格式的模型,为啥一团黑?

答:这个应该是没有读取到贴图文件。贴图文件和obj文件需要在同级目录下面。 DasViewer是由大势智慧自主研发的免费的实景三维模型浏览器,采用多细节层次模型逐步自适应加载技术,让用户在极低的电脑配置下,也能流畅的加载较大规模实景三维模型,提供方便快捷的数据浏览操作。 免…...

【05】LLaMA-Factory微调大模型——初尝微调模型

上文【04】LLaMA-Factory微调大模型——数据准备介绍了如何准备指令监督微调数据&#xff0c;为后续的微调模型提供高质量、格式规范的数据支撑。本文将正式进入模型微调阶段&#xff0c;构建法律垂直应用大模型。 一、硬件依赖 LLaMA-Factory框架对硬件和软件的依赖可见以下…...

Training for Stable Diffusion

1.Training for Stable Diffusion 笔记来源&#xff1a; 1.Denoising Diffusion Probabilistic Models 2.最大似然估计(Maximum likelihood estimation) 3.Understanding Maximum Likelihood Estimation 4.How to Solve ‘CUDA out of memory’ in PyTorch 5.pytorch-stable-d…...

初学51单片机之指针基础与串口通信应用

开始之前推荐一个电路学习软件&#xff0c;这个软件笔者也刚接触。名字是Circuit有在线版本和不在线版本&#xff0c;这是笔者在B站看视频翻到的。 Paul Falstadhttps://www.falstad.com/这是地址。 离线版本在网站内点这个进去 根据你的系统下载你需要的版本红线的是windows…...

【启明智显分享】甲醛检测仪HMI方案:ESP32-S3方案4.3寸触摸串口屏,RS485、WIFI/蓝牙可选

今年&#xff0c;“串串房”一词频繁引发广大网友关注。“串串房”&#xff0c;也被称为“陷阱房”“贩子房”——炒房客以低价收购旧房子或者毛坯房&#xff0c;用极度节省成本的方式对房子进行装修&#xff0c;之后作为精修房高价租售&#xff0c;因甲醛等有害物质含量极高&a…...

Linux 驱动学习笔记

1、驱动程序分为几类&#xff1f; • 内核驱动程序&#xff08;Kernel Drivers&#xff09;&#xff1a;这些是运行在操作系统内核空间的驱动程序&#xff0c;用于直接访问和控制硬件设备。它们提供了与硬件交互的底层功能&#xff0c;如处理中断、访问寄存器、数据传输等。 •…...

ip地址设置了重启又改变了怎么回事

在数字世界的浩瀚星海中&#xff0c;IP地址就如同每个设备的“身份证”&#xff0c;确保它们在网络中准确无误地定位与通信。然而&#xff0c;当我们精心为设备配置好IP地址后&#xff0c;却时常遭遇一个令人费解的现象&#xff1a;一旦设备重启&#xff0c;原本设定的IP地址竟…...

layui table 浮动操作内容收缩,展开

layui table 隐藏浮动操作内容 fixed: right, style:, title: 操作,align:left, minWidth: 450, toolbar:#id分析&#xff1a; 浮动一块新增一个class layui-table-fixed-r 可以隐藏整块内容进行&#xff0c;新增一个按钮点击时间&#xff0c;然后进行收缩和展开 $(‘.layui-…...

Ubuntu24.04 NFS 服务配置

1、NFS 介绍 NFS 是 Network FileSystem 的缩写&#xff0c;顾名思义就是网络文件存储系统&#xff0c;它允许网络中的计算机之间通过 TCP/IP 网络共享资源。通过 NFS&#xff0c;我们本地 NFS 的客户端应用可以透明地读写位于服务端 NFS 服务器上的文件&#xff0c;就像访问本…...

vue3使用html2canvas

安装 yarn add html2canvas 代码 <template><div class"container" ref"container"><div class"left"><img :src"logo" alt"" class"logo"><h2>Contractors pass/承包商通行证&l…...

OpenCV分水岭算法watershed函数的使用

操作系统&#xff1a;ubuntu22.04 OpenCV版本&#xff1a;OpenCV4.9 IDE:Visual Studio Code 编程语言&#xff1a;C11 描述 我们将学会使用基于标记的分水岭算法来进行图像分割。我们将看到&#xff1a;watershed()函数的用法。 任何灰度图像都可以被视为一个地形表…...