可用累积概率法将权重转为不重叠区间,再用math.random()命中对应区间实现加权随机选择;例如权重[3,5,2]归一化后得累积区间[0,0.3)、[0.3,0.8)、[0.8,1.0),遍历或二分查找即可高效选取任务。

可以用累积概率法把权重转成区间,再用 Math.random() 生成 [0,1) 的随机数去“命中”对应区间,从而实现按权重分配任务。
把权重归一化为累积概率区间
假设有三个任务 A、B、C,权重分别是 3、5、2。先算总和(3+5+2=10),再依次计算每个任务的**累积概率上界**:
- A:3/10 = 0.3 → 区间 [0, 0.3)
- B:(3+5)/10 = 0.8 → 区间 [0.3, 0.8)
- C:(3+5+2)/10 = 1.0 → 区间 [0.8, 1.0)
这样就把权重映射成了不重叠、全覆盖的连续区间。
用 Math.random() 查找命中区间
Math.random() 每次返回一个 [0, 1) 内的浮点数。只需遍历累积概率数组,找到第一个“上界 > 随机数”的任务即可:
const weights = [3, 5, 2];
const tasks = ['A', 'B', 'C'];
<p>// 构建累积概率数组
const total = weights.reduce((a, b) => a + b, 0);
const cumProbs = [];
let sum = 0;
for (const w of weights) {
sum += w / total;
cumProbs.push(sum);
}</p><p>// 抽取任务
function selectTask() {
const r = Math.random();
for (let i = 0; i </p><h3>优化:用二分查找提升大数据量性能</h3><p>当任务数很多(比如上百个)时,线性遍历变慢。因累积概率数组天然有序,可用二分查找把时间复杂度从 O(n) 降到 O(log n):</p>
- 不用改数据结构,仍用同一个
cumProbs数组 - 写一个简单的二分函数,找第一个 ≥
r的索引 - 对 1000 个任务,平均比较次数从 ~500 次降到 ~10 次
注意事项与常见坑
别直接用 Math.random() * weight —— 这会导致高权重重叠、低权重被压缩,实际概率不是正比于权重。
浮点误差一般可忽略,但若要求严格(如金融场景),可改用整数随机(Math.floor(Math.random() * total)),再做前缀和查找。
权重支持动态更新:只要每次调用前重新计算 cumProbs,就能适应权重实时变化的场景(比如根据服务器负载调整任务分发比例)。










