当前位置: 首页
编程语言
C++实现带权重轮询调度算法 _ 状态保持与权重分布逻辑【源码】

C++实现带权重轮询调度算法 _ 状态保持与权重分布逻辑【源码】

热心网友 时间:2026-04-30
转载

C++实现带权重轮询调度算法 _ 状态保持与权重分布逻辑【源码】

C++实现带权重轮询调度算法 _ 状态保持与权重分布逻辑【源码】

免费影视、动漫、音乐、游戏、小说资源长期稳定更新! 👉 点此立即查看 👈

轮询状态必须用可变对象保存,不能每次重算

这里有个常见的误区:以为权重轮询就是简单地按比例重复节点。其实不然,它的核心在于维护每个节点的“当前权重”和“已分配次数”这两种动态状态。如果每次调度都图省事,从头计算类似 current_weight = weight * (1 - allocated / total_allocated) 这样的公式,历史分配的节奏就全丢了,结果就是在短周期内,请求会严重地向某个节点倾斜,完全违背了平滑分布的初衷。

实际实现中,用 std::vector 来存储节点的元数据(比如 weightcurrent_weightindex)是成本最低的方案。当然,用 struct Server 封装一下会更清晰,但千万要留神,别顺手把 current_weight 声明成 const 或者只读字段——它可是要频繁变动的。

get_next_server() 的核心逻辑:加权最大值选取 + 状态衰减

标准的实现流程是这样的:每一轮调度,先遍历所有节点,给每个节点的 current_weight 加上它自己的原始 weight。接着,从所有节点里选出 current_weight 最大的那个作为本次结果。最后,也是最关键的一步:将这个被选中节点的 current_weight 减去所有节点的权重总和(sum_weights)。

这个“先加权增、再选最大、最后整体回退”的操作,本质上是在用离散的整数运算,去逼近一个理想的连续分数调度器。有几个细节必须卡死:

  • current_weight 的初始值必须全部设为0,而不是初始化为 weight
  • “减去总权重和”这个操作,必须在选出节点之后执行,顺序一旦颠倒,整个权重的平衡就会被打破,产生漂移。
  • 如果某个节点的权重被设为0,一定要跳过它,否则它的 current_weight 会持续负增长,干扰正常的比较逻辑。
  • 当多个节点的 current_weight 相等时,通常按索引升序选择,以保证结果的确定性。

权重归一化不是必须的,但不归一化会影响浮点精度和整数溢出

直接使用整数权重(比如3、5、2)进行运算是最稳妥的。如果原始权重是小数(例如0.3、0.5、0.2),必须先放大转换成整数(比如乘以100,变成30、50、20)。否则,用 double 类型累加,几轮之后微小的误差就会累积起来,导致排序错乱,该选的节点没选上。反过来,刻意去做归一化(把所有权重除以总和)反而没有意义——算法只依赖权重之间的相对大小,归一化不仅多此一举,还会引入额外的计算误差。

实践中,下面这几个坑经常遇到:

  • float 存储 current_weight:通常3到4轮循环后,累积误差就可能超过0.01,导致本该在第3次被选中的节点意外被跳过。
  • 权重和过大:比如单个节点权重就是10亿,总共100个节点,current_weight 累加几次就可能溢出 int32_t 的范围,这时必须使用 int64_t
  • 动态增删节点时,如果忘了同步调整 current_weight 状态数组的长度,很容易引发访问越界。

状态保持要跨调用生命周期,推荐封装成类而非函数静态变量

有些偷懒的做法,是在函数内部用一个 static std::vector state 来维持状态。这看似简单,却埋下了两个隐患:第一,多线程环境下不安全;第二,它无法支持多个独立的调度器实例(想象一下,你的系统里同时有多个不同的服务集群,每个都需要一套独立的权重配置)。

更专业的做法是定义一个 class WeightedRoundRobin。把 std::vector 和总权重 sum_weights 作为成员变量。构造函数接受一个 std::vector weights 参数来完成初始化;对外则提供一个 next() 方法来返回选中的节点索引或指针。这里还有几点需要注意:

  • 避免在 next() 方法内部进行深拷贝或字符串拼接这类操作,防止引入隐性的性能开销。
  • 如果需要线程安全,建议对 current_weight 的更新操作使用 std::atomic_int64_t 或更细粒度的互斥锁,而不是简单粗暴地给整个 next() 方法加上大锁。
  • 调试阶段,可以在 next() 返回前打印出 current_weight 数组,观察其变化,验证分布是否平滑收敛。例如,对于权重 [3, 5, 2],长期调用的频率应该稳定在近似3:5:2的比例。

说到底,权重轮询算法真正的难点,不在于理解公式,而在于确保 current_weight 在整数域里能够稳定地“震荡”而不发生“漂移”。只要有一次加法或减法的顺序搞错,后面的所有调度都会错位。所以,在上线之前,务必用一组固定的权重序列,模拟运行个上千轮,然后统计各节点出现的频次。如果误差超过±5%,那就得好好检查一下状态更新的路径是不是哪里出了岔子。

来源:https://www.php.cn/faq/2393455.html

游乐网为非赢利性网站,所展示的游戏/软件/文章内容均来自于互联网或第三方用户上传分享,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系youleyoucom@outlook.com。

同类文章
更多
如何在 Java 中使用 ExecutorCompletionService 按照异步任务完成的先后顺序获取返回结果

如何在 Java 中使用 ExecutorCompletionService 按照异步任务完成的先后顺序获取返回结果

如何在 Ja va 中使用 ExecutorCompletionService 按照异步任务完成的先后顺序获取返回结果 处理异步任务时,你是否遇到过这样的困扰:提交了一堆任务,却只能按照提交顺序一个个等待结果,即便后面的任务先完成了也得干等着?这在处理网络请求或I O操作时尤其低效。好在Ja va并

时间:2026-04-30 11:15
怎么利用 java.util.Arrays.mismatch() 快速找出两个配置数组中第一个不一致的配置项

怎么利用 java.util.Arrays.mismatch() 快速找出两个配置数组中第一个不一致的配置项

如何用 Arrays mismatch() 快速定位配置数组的首个差异项 在配置比对或数据校验的场景里,你是不是也写过循环来逐项比较两个数组?其实,直接用 Arrays mismatch() 就能一步到位,精准锁定第一个差异点的索引。这个方法简直就是为“找不同”量身定制的,不仅代码更简洁,还内置了空

时间:2026-04-30 11:15
Spring Boot 中实现表单提交下的抽象类多态反序列化

Spring Boot 中实现表单提交下的抽象类多态反序列化

Spring Boot 中实现表单提交下的抽象类多态反序列化 本文介绍如何在 application x-www-form-urlencoded 请求场景下,基于 discriminator 字段动态反序列化为具体子类,绕过 spring 默认无法实例化抽象类的限制。 今天我们来聊聊一个Spring

时间:2026-04-30 11:15
怎么利用 Maven 的 Profile 功能实现开发、测试与生产环境的配置切换

怎么利用 Maven 的 Profile 功能实现开发、测试与生产环境的配置切换

怎么利用 Ma ven 的 Profile 功能实现开发、测试与生产环境的配置切换 Profile 必须显式用 -P 激活,IDE 不会自动读取 pom xml 里的 activeByDefault 先说一个核心判断:指望 IDE 自动识别 pom xml 里那个 true 标签,这事儿基本不靠谱。

时间:2026-04-30 11:15
怎么在 Java 中声明并初始化基础数据类型(int, double, boolean)

怎么在 Java 中声明并初始化基础数据类型(int, double, boolean)

怎么在 Ja va 中声明并初始化基础数据类型(int, double, boolean) 声明并初始化 int 变量时,别漏掉分号和类型关键字 Ja va 的强类型特性,意味着每个变量都必须有明确的“身份”。int 就是 int,不能像 Ja vaScript 那样用一个 let 或 var 就糊

时间:2026-04-30 11:14
热门专题
更多
刀塔传奇破解版无限钻石下载大全 刀塔传奇破解版无限钻石下载大全
洛克王国正式正版手游下载安装大全 洛克王国正式正版手游下载安装大全
思美人手游下载专区 思美人手游下载专区
好玩的阿拉德之怒游戏下载合集 好玩的阿拉德之怒游戏下载合集
不思议迷宫手游下载合集 不思议迷宫手游下载合集
百宝袋汉化组游戏最新合集 百宝袋汉化组游戏最新合集
jsk游戏合集30款游戏大全 jsk游戏合集30款游戏大全
宾果消消消原版下载大全 宾果消消消原版下载大全
  • 日榜
  • 周榜
  • 月榜
热门教程
更多
  • 游戏攻略
  • 安卓教程
  • 苹果教程
  • 电脑教程