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

Dubbo 源码解读:负载均衡策略

概览

org.apache.dubbo包下META-INF/dubbo/internal/org.apache.dubbo.rpc.cluster.LoadBalance中内部spi实现类有以下几种:

random=org.apache.dubbo.rpc.cluster.loadbalance.RandomLoadBalance
roundrobin=org.apache.dubbo.rpc.cluster.loadbalance.RoundRobinLoadBalance
leastactive=org.apache.dubbo.rpc.cluster.loadbalance.LeastActiveLoadBalance
consistenthash=org.apache.dubbo.rpc.cluster.loadbalance.ConsistentHashLoadBalance
shortestresponse=org.apache.dubbo.rpc.cluster.loadbalance.ShortestResponseLoadBalance

在这里插入图片描述
通过ConsumerConfig可设置负载均衡策略:

		...//<editor-fold desc="consumer 配置">// 负载均衡策略// * random - 随机;// * roundrobin - 轮询;// * leastactive - 最少活跃调用;// * consistenthash - 哈希一致 (2.1.0以上版本);// * shortestresponse - 最短响应 (2.7.7以上版本);ConsumerConfig consumerConfig = new ConsumerConfig();consumerConfig.setLoadbalance("roundrobin");//</editor-fold>...

另外,对于加权随机,加权轮询等策略都集成自以上的策略中,consumer会检查注册中心中provider是否提供weight参数自动开启加权负载均衡。除了哈希一致策略,其他的均有加权版本(不提供weight参数即权重一样)。

在provider端,我们可以设置ServiceConfig中设置weight,注意:在RegistryConfig中也可以设置weight,不过这是在多注册中心的环境下对该注册中心负载均衡的权重,不是某个服务调用的负载均衡权重。

		//<editor-fold desc="服务配置">ServiceConfig<GreetingsService> hiConfig = new ServiceConfig<>();hiConfig.setInterface(GreetingsService.class);hiConfig.setRef(new GreetingsServiceImpl());// 权重hiConfig.setWeight(2);//</editor-fold>//<editor-fold desc="registry配置">RegistryConfig registryConfig = new RegistryConfig();registryConfig.setAddress("zookeeper://127.0.0.1:2181");// 多个registry时,该registry的权重registryConfig.setWeight(2);//</editor-fold>

此时,zk为例注册的服务如下:
在这里插入图片描述
该节点名称最后会显示weight参数:

dubbo%3A%2F%2F192.168.247.1%3A20880%2Forg.example.protocol.dubbo.GreetingsService%3Fanyhost%3Dtrue%26application%3Dfirst-dubbo-provider%26application.version%3D1.0.0%26background%3Dfalse%26deprecated%3Dfalse%26dubbo%3D2.0.2%26dynamic%3Dtrue%26generic%3Dfalse%26interface%3Dorg.example.protocol.dubbo.GreetingsService%26methods%3DsayHi%26owner%3Dbty%26pid%3D2716%26release%3D3.1.6%26service-name-mapping%3Dtrue%26side%3Dprovider%26timestamp%3D1677208111268%26weight%3D2

AbstractLoadBalance

该abstract类只有一个作用:获取provider的权重,提升代码复用率。
注:如果provider没有提供weight参数,则默认为100.
其中,randomroundrobin加权时每次都起作用;而leastactiveshortestresponse是在存在符合选取条件的provider有多个时使用加权随机在其中选一个;consistenthash没用到。

RandomLoadBalance


public class RandomLoadBalance extends AbstractLoadBalance {// invokers代表需要负载均衡的provider列表// URL代表该consumer的metadata,和zk中/dubbo/metadata/com.xxx.service/consumer/xxx-consumer节点内容相同@Overrideprotected <T> Invoker<T> doSelect(List<Invoker<T>> invokers, URL url, Invocation invocation) {// Number of invokersint length = invokers.size();// 根据从registry拿到的参数中寻找是否有weight参数或timestamp参数来判断// 是否需要加权操作if (!needWeightLoadBalance(invokers, invocation)) {// 没有直接random选取return invokers.get(ThreadLocalRandom.current().nextInt(length));}// 标志位,权重是否都一样boolean sameWeight = true;// weights序列,不过 weights[i]是0到i的provider节点实际weight的和// 如:// 节点索引i    : 0    1    2// 节点i的weight: 2    3    5//  weights[i] : 2  2+3=5 2+3+5=10// 应该叫weightSum更合适// 这是为了后面随机选取节点用,随机数大小落入哪个区间,就选哪个节点int[] weights = new int[length];// The sum of weightsint totalWeight = 0;for (int i = 0; i < length; i++) {int weight = getWeight(invokers.get(i), invocation);// SumtotalWeight += weight;// save for later useweights[i] = totalWeight;// 如果当前weight不是之前weight的和的索引倍数,则清空same标志// 索引:   0    1    2//   w:    3    3    2// total:  3    6    8// w*(i+1) 3    6    6//  same?  √    √    ×if (sameWeight && totalWeight != weight * (i + 1)) {sameWeight = false;}}// 如果权重不等 且 至少有一个invoker的权重大于0if (totalWeight > 0 && !sameWeight) {// 根据权重和计算随机offsetint offset = ThreadLocalRandom.current().nextInt(totalWeight);// Return a invoker based on the random value.for (int i = 0; i < length; i++) {// 选取第一个小于offset的节点i做调用if (offset < weights[i]) {return invokers.get(i);}}}// 权重相等return invokers.get(ThreadLocalRandom.current().nextInt(length));}}

ThreadLocalRandom随机数生成

RandomLoadBalance中随机数生成使用ThreadLocalRandom,该类始于JDK1.7,由Doug Lea操刀编写。

优点:When applicable, use of ThreadLocalRandom rather than shared Random objects in concurrent programs will typically encounter much less overhead and contention.
用法:ThreadLocalRandom.current().nextX(…) (where X is Int, Long, etc).
缺点:Instances of ThreadLocalRandom are not cryptographically secure. Consider instead using java.security.SecureRandom in security-sensitive applications. Additionally, default-constructed instances do not use a cryptographically random seed unless the system property java.util.secureRandomSeed is set to true.

RoundRobinLoadBalance

public class RoundRobinLoadBalance extends AbstractLoadBalance {protected static class WeightedRoundRobin {private int weight;private AtomicLong current = new AtomicLong(0);private long lastUpdate;...// 每次加一个权值public long increaseCurrent() {return current.addAndGet(weight);}}...// 接口名称:<providerId:WeightedRoundRobin>// 如:// org.example.protocol.dubbo.GreetingsService.sayHi : < dubbo://192.168.247.1:20882/org.example.protocol.dubbo.GreetingsService , WeightedRoundRobin >private ConcurrentMap<String, ConcurrentMap<String, WeightedRoundRobin>> methodWeightMap = new ConcurrentHashMap<String, ConcurrentMap<String, WeightedRoundRobin>>();...@Overrideprotected <T> Invoker<T> doSelect(List<Invoker<T>> invokers, URL url, Invocation invocation) {// <接口.方法>,如org.example.protocol.dubbo.GreetingsService.sayHiString key = invokers.get(0).getUrl().getServiceKey() + "." + invocation.getMethodName();// 初始化ConcurrentMap<String, WeightedRoundRobin> map = methodWeightMap.computeIfAbsent(key, k -> new ConcurrentHashMap<>());// 权重和int totalWeight = 0;// 记录当前最大值long maxCurrent = Long.MIN_VALUE;// 记录更新时间,一个接口的所有provider的时间都一样。long now = System.currentTimeMillis();// 选中的Invoker<T> selectedInvoker = null;// 选中的WeightedRoundRobin selectedWRR = null;// 每次都会循环一遍,不会中途退出for (Invoker<T> invoker : invokers) {// dubbo://192.168.247.1:20882/org.example.protocol.dubbo.GreetingsServiceString identifyString = invoker.getUrl().toIdentityString();// 获取权重,如果没有权重,则默认权重都一样,均为100int weight = getWeight(invoker, invocation);// 没有缓存,则为GreetingsService的这个provider设置weight,生成WeightedRoundRobin对象// 缓存了直接获取WeightedRoundRobin weightedRoundRobin = map.computeIfAbsent(identifyString, k -> {			WeightedRoundRobin wrr = new WeightedRoundRobin();wrr.setWeight(weight);return wrr;});// 缓存的WeightedRoundRobin可能会过时,这里判定以下,保持最新的weightif (weight != weightedRoundRobin.getWeight()) {//weight changedweightedRoundRobin.setWeight(weight);}// 更新// 每次每个provider都会先增加自己权重的值long cur = weightedRoundRobin.increaseCurrent();// 标记更新时间weightedRoundRobin.setLastUpdate(now);// 如果当前值大于最大值,则选取if (cur > maxCurrent) {maxCurrent = cur;selectedInvoker = invoker;selectedWRR = weightedRoundRobin;}// totalWeight += weight;}if (invokers.size() != map.size()) {map.entrySet().removeIf(item -> now - item.getValue().getLastUpdate() > RECYCLE_PERIOD);}if (selectedInvoker != null) {// 注意,选中的weightedRoundRobin的current会减去totalWeight;selectedWRR.sel(totalWeight);return selectedInvoker;}// should not happen herereturn invokers.get(0);}
}

轮询算法流程

在这里插入图片描述

轮次结果
0在这里插入图片描述
1在这里插入图片描述
2在这里插入图片描述
3在这里插入图片描述
4在这里插入图片描述
5在这里插入图片描述
6在这里插入图片描述

可以看到调用顺序为:A→\rightarrowB→\rightarrowA→\rightarrowC→\rightarrowB→\rightarrowA。

LeastActiveLoadBalance

按照最小调用次数优先的方式选provider,如果存在多个则加权随机选取。
Active等参数由RpcStatus提供,记录RpcStatus的工作由ActiveLimitFilter完成

public class LeastActiveLoadBalance extends AbstractLoadBalance {@Overrideprotected <T> Invoker<T> doSelect(List<Invoker<T>> invokers, URL url, Invocation invocation) {// Number of invokersint length = invokers.size();// The least active value of all invokersint leastActive = -1;// The number of invokers having the same least active value (leastActive)int leastCount = 0;// 存储所有具有相同least active value的invoker的index,数组长度==leastCountint[] leastIndexes = new int[length];// the weight of every invokersint[] weights = new int[length];// The sum of the warmup weights of all the least active invokersint totalWeight = 0;// The weight of the first least active invokerint firstWeight = 0;// Every least active invoker has the same weight value?boolean sameWeight = true;// 过滤找到调用次数最少的provider,可能存在多个providerfor (int i = 0; i < length; i++) {Invoker<T> invoker = invokers.get(i);// Get the active number of the invokerint active = RpcStatus.getStatus(invoker.getUrl(), invocation.getMethodName()).getActive();// 获取权重参数,provider没有提供则默认100int afterWarmup = getWeight(invoker, invocation);weights[i] = afterWarmup;// 如果是第一次调用,或当前active小于最小的,设置新的leastActiveif (leastActive == -1 || active < leastActive) {...} else // 多个leastActiveif (active == leastActive) {...}}// 如果符合最少调用次数的provider只有一个,直接返回if (leastCount == 1) {return invokers.get(leastIndexes[0]);}// if (!sameWeight && totalWeight > 0) {// 权重不等且totalWeight>0则利用权重随机选取int offsetWeight = ThreadLocalRandom.current().nextInt(totalWeight);// Return a invoker based on the random value.for (int i = 0; i < leastCount; i++) {// 找到相同权重的provider第一个比随机选取的offsetWeight大的providerint leastIndex = leastIndexes[i];offsetWeight -= weights[leastIndex];if (offsetWeight < 0) {return invokers.get(leastIndex);}}}// 如果所有provider的weight相同或totalWeight==0则随机选取.return invokers.get(leastIndexes[ThreadLocalRandom.current().nextInt(leastCount)]);}}

ShortestResponseLoadBalance

同上,利用RpcStatus中获取的参数选取响应最低的provider(滑动时间窗口内),存在多个则加权随机选取。

ConsistentHashLoadBalance

public class ConsistentHashLoadBalance extends AbstractLoadBalance {// 对每一个接口方法缓存一个ConsistentHashSelector// key为interface.methodNameprivate final ConcurrentMap<String, ConsistentHashSelector<?>> selectors = new ConcurrentHashMap<String, ConsistentHashSelector<?>>();@Overrideprotected <T> Invoker<T> doSelect(List<Invoker<T>> invokers, URL url, Invocation invocation) {String methodName = RpcUtils.getMethodName(invocation);String key = invokers.get(0).getUrl().getServiceKey() + "." + methodName;// 用来代表List<Invoker<T>>,如果内容变化,则该hashcode也变化,为了保持缓存一致性int invokersHashCode = invokers.hashCode();ConsistentHashSelector<T> selector = (ConsistentHashSelector<T>) selectors.get(key);// 缓存的ConsistentHashSelector为空,或已经过期if (selector == null || selector.identityHashCode != invokersHashCode) {selectors.put(key, new ConsistentHashSelector<T>(invokers, methodName, invokersHashCode));selector = (ConsistentHashSelector<T>) selectors.get(key);}return selector.select(invocation);}private static final class ConsistentHashSelector<T> {// 虚拟节点和Invoker对应关系private final TreeMap<Long, Invoker<T>> virtualInvokers;// 一致性哈希,哈希环虚拟节点个数private final int replicaNumber;private final int identityHashCode;// select时候以方法的那个参数为key进行hash映射到hash环,默认第一个参数private final int[] argumentIndex;ConsistentHashSelector(List<Invoker<T>> invokers, String methodName, int identityHashCode) {this.virtualInvokers = new TreeMap<Long, Invoker<T>>();this.identityHashCode = identityHashCode;URL url = invokers.get(0).getUrl();// 如果hash.nodes没有指定,默认每个provider160个节点this.replicaNumber = url.getMethodParameter(methodName, HASH_NODES, 160);String[] index = COMMA_SPLIT_PATTERN.split(url.getMethodParameter(methodName, HASH_ARGUMENTS, "0"));argumentIndex = new int[index.length];for (int i = 0; i < index.length; i++) {argumentIndex[i] = Integer.parseInt(index[i]);}// 为每个invoker分配哈希环160个虚拟节点for (Invoker<T> invoker : invokers) {String address = invoker.getUrl().getAddress();for (int i = 0; i < replicaNumber / 4; i++) {byte[] digest = Bytes.getMD5(address + i);for (int h = 0; h < 4; h++) {long m = hash(digest, h);virtualInvokers.put(m, invoker);}}}}public Invoker<T> select(Invocation invocation) {boolean isGeneric = invocation.getMethodName().equals($INVOKE);// 获取此次invocation的hash的keyString key = toKey(invocation.getArguments(),isGeneric); byte[] digest = Bytes.getMD5(key);// 映射return selectForKey(hash(digest, 0));}}
}

相关文章:

Dubbo 源码解读:负载均衡策略

概览 org.apache.dubbo包下META-INF/dubbo/internal/org.apache.dubbo.rpc.cluster.LoadBalance中内部spi实现类有以下几种&#xff1a; randomorg.apache.dubbo.rpc.cluster.loadbalance.RandomLoadBalance roundrobinorg.apache.dubbo.rpc.cluster.loadbalance.RoundRobinL…...

吃瓜教程笔记—Task04

神经网络 知识点 M-P神经元 模型如图所示&#xff1a;  神经元的工作机理&#xff1a;神经元接收来到n个其他神经元传递过来的输入信号&#xff0c;这些输入信号通过带权重的连接进行传递&#xff0c;神经元接收到的总输入值将与神经元的阈值进行比较&#xff0c;然后通过…...

进程地址空间(虚拟地址空间)

目录 引入问题 测试代码 引入地址空间 故事1&#xff1a; 故事二&#xff1a; 解决问题 为什么有虚拟地址空间 扩展 扩展1&#xff08;没有地址空间&#xff0c;OS如何工作&#xff09; 扩展2 &#xff08;代码只读深入了解&#xff09; 扩展3&#xff08;malloc本质…...

【项目精选】基于Vue + ECharts的数据可视化系统的设计与实现(论文+源码+视频)

今天给小伙伴们推荐一款超优秀的全新Vue3.0大数据系统Vue3-bigData。 点击下载源码 vue3-bigdata 基于vue3.0echarts构建的可视化大屏图表展示系统。包括各种可视化图表及Vue3新API使用。 功能 柱状图、饼图、词云图、漏斗图 水球图、折线图 仪表盘、雷达图 矩形树图、关系…...

JavaScript Window Screen

文章目录JavaScript Window ScreenWindow ScreenWindow Screen 可用宽度Window Screen 可用高度JavaScript Window Screen window.screen 对象包含有关用户屏幕的信息。 Window Screen window.screen对象在编写时可以不使用 window 这个前缀。 一些属性&#xff1a; screen…...

【双重注意机制:肺癌:超分】

Dual attention mechanism network for lung cancer images super-resolution &#xff08;肺癌图像超分辨率的双重注意机制网络&#xff09; 目前&#xff0c;肺癌的发病率和死亡率均居世界恶性肿瘤之首。提高肺部薄层CT的分辨率对于肺癌筛查的早期诊断尤为重要。针对超分辨…...

各种中间件的使用

init background 这一部分我们学习一些常用的&#xff0c; 但是不需要深入理解的中间件 &#xff0c; 例如kafka ,分布式文件系统。 summary Content what is kafka? What time to used it ? 其实消息队列就是解决系统之间复杂交互例如聊天系统和交易系统&#xff0c; …...

Systemverilog覆盖率的合并和计算方式

在systemverilog中&#xff0c;对于一个covergroup来说&#xff0c;可能会有多个instance&#xff0c;我们可能需要对这些instance覆盖率进行操作。 只保存covergroup type的覆盖率&#xff0c;不需要保存instance-specified的覆盖率coverage type和instance-specified的覆盖率…...

(周末公众号解读系列)2000字-视觉SLAM综述

参考链接&#xff1a;https://mp.weixin.qq.com/s?__bizMzg2NzUxNTU1OA&mid2247528395&idx1&sn6c9290dd7fd926f11cbaca312fbe99a2&chksmceb84202f9cfcb1410353c805b122e8df2e2b79bd4031ddc5d8678f8b11c356a25f55f488907&scene126&sessionid1677323905…...

力扣29-两数相除

29. 两数相除 给你两个整数&#xff0c;被除数 dividend 和除数 divisor。将两数相除&#xff0c;要求 不使用 乘法、除法和取余运算。 整数除法应该向零截断&#xff0c;也就是截去&#xff08;truncate&#xff09;其小数部分。例如&#xff0c;8.345 将被截断为 8 &#x…...

【MindSpore】安装和使用MindSpore 2.0.0版本简单实现数据变换Transforms功能

本篇文章主要是讲讲MindSpore的安装以及根据官方提供的例子实现数据变换功能。 昇思MindSpore是一款开源的AI框架&#xff0c;旨在实现易开发、高效执行、全场景覆盖三大目标。 目录1、加入MindSpore社区2、安装前准备2.1、获取安装命令2.2、安装pip2.3、确认系统环境3、安装Mi…...

PRML笔记4-绪论中推断和决策小结

在推断阶段使用训练数据学习后验概率p(Ck∣x)p(\mathcal{C_k}|\boldsymbol{x})p(Ck​∣x)的模型&#xff1b;在决策阶段使用后验概率进行最优的分类&#xff1b;亦或是同时解决推断和决策问题&#xff0c;简单的学习一个函数f(x)f(\boldsymbol{x})f(x)&#xff0c;将输入x\bold…...

DSPE-PEG-Streptavidin;Streptavidin-PEG-DSPE;磷脂聚乙二醇链霉亲和素,科研用试剂

DSPE-PEG-Streptavidin 中文名称&#xff1a;二硬脂酰基磷脂酰乙醇胺-聚乙二醇-链霉亲和素 中文别名&#xff1a;磷脂-聚乙二醇-链霉亲和素&#xff1b;链霉亲和素PEG磷脂 英文常用名&#xff1a;DSPE-PEG-Streptavidin&#xff1b;Streptavidin-PEG-DSPE 外观&#xff1a;粉…...

Java中的Stream

Stream流的特点 中间操作返回的是Stream类型&#xff0c;终结操作返回的是void 中间操作的这个Lazy指的是增加待处理操作&#xff0c;而不会真的处理&#xff08;放队列里&#xff09;&#xff0c;集合中的数据并未实际改变&#xff0c;到终结操作的时候才会把这些放队列里的操…...

【数据库】关系数据理论

第六章关系数据理论 [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-r9ETJ75y-1677334548439)(imgs/image-20220508202554924.png)] 数据依赖 是一个关系内部属性与属性之间的一种约束关系 函数依赖多值依赖 函数依赖 [外链图片转存失败,源站可…...

初阶C语言——结构体【详解】

文章目录1. 结构体的声明1.1 结构的基础知识1.2 结构的声明1.3 结构成员的类型1.4 结构体变量的定义和初始化2. 结构体成员的访问3. 结构体传参1. 结构体的声明 1.1 结构的基础知识 结构是一些值的集合&#xff0c;这些值称为成员变量。结构的每个成员可以是不同类型的变量。 …...

盘点:9款身份和访问管理工具

身份和访问管理&#xff08;IAM&#xff09;长期以来一直是安全领导者职业生涯的关键“试炼场”&#xff0c;许多人在身份技术部署方面做出了事关成败的决定。 确保安全访问和身份管理是网络安全态势的两大基础 。同时&#xff0c;人员、应用程序和系统登录的方式以及它们彼此集…...

Linux下的进程地址空间

Linux下的进程地址空间程序地址空间回顾从代码结果推结论引入进程地址空间页表为什么要有进程地址空间重新理解进程地址空间程序地址空间回顾 我们在初学C/C的时候&#xff0c;我们会经常看见老师们画这样的内存布局图&#xff1a; 可是这真的是内存吗&#xff1f; 如果不是它…...

Web Spider Ast-Hook 浏览器内存漫游 - 数据检索

文章目录一、资源下载二、通过npm安装anyproxy模块三、anyproxy的介绍以及基本使用1. anyproxy的功能介绍2. anyproxy的基本使用四、给浏览器挂代理五、实操极验demo案例总结提示&#xff1a;以下是本篇文章正文内容&#xff0c;下面案例可供参考 一、资源下载 Github&#x…...

开源启智,筑梦未来!第四届OpenI/O启智开发者大会开幕

2023年2月24日&#xff0c;第四届OpenI/O启智开发者大会在深圳顺利开幕。本次活动由鹏城实验室、新一代人工智能产业技术创新战略联盟&#xff08;AITISA&#xff09;主办&#xff0c;OpenI启智社区、中关村视听产业技术创新联盟&#xff08;AVSA&#xff09;承办&#xff0c;华…...

HTML 语义化

目录 HTML 语义化HTML5 新特性HTML 语义化的好处语义化标签的使用场景最佳实践 HTML 语义化 HTML5 新特性 标准答案&#xff1a; 语义化标签&#xff1a; <header>&#xff1a;页头<nav>&#xff1a;导航<main>&#xff1a;主要内容<article>&#x…...

微信小程序之bind和catch

这两个呢&#xff0c;都是绑定事件用的&#xff0c;具体使用有些小区别。 官方文档&#xff1a; 事件冒泡处理不同 bind&#xff1a;绑定的事件会向上冒泡&#xff0c;即触发当前组件的事件后&#xff0c;还会继续触发父组件的相同事件。例如&#xff0c;有一个子视图绑定了b…...

STM32F4基本定时器使用和原理详解

STM32F4基本定时器使用和原理详解 前言如何确定定时器挂载在哪条时钟线上配置及使用方法参数配置PrescalerCounter ModeCounter Periodauto-reload preloadTrigger Event Selection 中断配置生成的代码及使用方法初始化代码基本定时器触发DCA或者ADC的代码讲解中断代码定时启动…...

项目部署到Linux上时遇到的错误(Redis,MySQL,无法正确连接,地址占用问题)

Redis无法正确连接 在运行jar包时出现了这样的错误 查询得知问题核心在于Redis连接失败&#xff0c;具体原因是客户端发送了密码认证请求&#xff0c;但Redis服务器未设置密码 1.为Redis设置密码&#xff08;匹配客户端配置&#xff09; 步骤&#xff1a; 1&#xff09;.修…...

听写流程自动化实践,轻量级教育辅助

随着智能教育工具的发展&#xff0c;越来越多的传统学习方式正在被数字化、自动化所优化。听写作为语文、英语等学科中重要的基础训练形式&#xff0c;也迎来了更高效的解决方案。 这是一款轻量但功能强大的听写辅助工具。它是基于本地词库与可选在线语音引擎构建&#xff0c;…...

服务器--宝塔命令

一、宝塔面板安装命令 ⚠️ 必须使用 root 用户 或 sudo 权限执行&#xff01; sudo su - 1. CentOS 系统&#xff1a; yum install -y wget && wget -O install.sh http://download.bt.cn/install/install_6.0.sh && sh install.sh2. Ubuntu / Debian 系统…...

推荐 github 项目:GeminiImageApp(图片生成方向,可以做一定的素材)

推荐 github 项目:GeminiImageApp(图片生成方向&#xff0c;可以做一定的素材) 这个项目能干嘛? 使用 gemini 2.0 的 api 和 google 其他的 api 来做衍生处理 简化和优化了文生图和图生图的行为(我的最主要) 并且有一些目标检测和切割(我用不到) 视频和 imagefx 因为没 a…...

排序算法总结(C++)

目录 一、稳定性二、排序算法选择、冒泡、插入排序归并排序随机快速排序堆排序基数排序计数排序 三、总结 一、稳定性 排序算法的稳定性是指&#xff1a;同样大小的样本 **&#xff08;同样大小的数据&#xff09;**在排序之后不会改变原始的相对次序。 稳定性对基础类型对象…...

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

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

Unity UGUI Button事件流程

场景结构 测试代码 public class TestBtn : MonoBehaviour {void Start(){var btn GetComponent<Button>();btn.onClick.AddListener(OnClick);}private void OnClick(){Debug.Log("666");}}当添加事件时 // 实例化一个ButtonClickedEvent的事件 [Formerl…...