C#实现平滑加权轮询WeightedRoundRobin
C#实现平滑加权轮询
作者:NewcatsHuang
时间:2022-01-22
完整代码:Github传送门
代码
WeightedRoundRobinHelper.cs
/// <summary>
/// 平滑加权轮询(需要实例化为单例)
/// </summary>
/// <typeparam name="T">节点值类型</typeparam>
public class WeightedRoundRobinHelper<T>
{
#region 字段
/// <summary>
/// 最大公约数
/// </summary>
private readonly int _gcd = 0;
/// <summary>
/// 最大权重值
/// </summary>
private readonly int _maxWeight = 0;
/// <summary>
/// 节点数
/// </summary>
private readonly int _nodesCount = 0;
/// <summary>
/// 当前权重
/// </summary>
private int _currentWeight = 0;
/// <summary>
/// 上次选中的节点
/// </summary>
private int _lastChosenNode = -1;
/// <summary>
/// 锁
/// </summary>
private SpinLock _sLock = new SpinLock(true);
/// <summary>
/// 节点
/// </summary>
private readonly List<WeightedNode<T>> _nodes;
#endregion
/// <summary>
/// 当前所有节点按权重正序排列之后序列化的json字符串的md5值(System.Text.Json的默认配置)
/// </summary>
public string Md5Value { get; set; }
/// <summary>
/// 构造函数
/// </summary>
/// <param name="nodes">节点</param>
public WeightedRoundRobinHelper(List<WeightedNode<T>> nodes)
{
_nodes = nodes.OrderBy(q => q.Weight).ToList();
_gcd = GetGcd(_nodes);
_maxWeight = GetMaxWeight(_nodes);
_nodesCount = _nodes.Count;
Md5Value = GetMd5(_nodes);
}
/// <summary>
/// 获取此次选择结果
/// </summary>
public WeightedNode<T> GetResult()
{
var isLocked = false;
_sLock.Enter(ref isLocked);
do
{
_lastChosenNode = (_lastChosenNode + 1) % _nodesCount;
if (_lastChosenNode == 0)
{
_currentWeight -= _gcd;
if (_currentWeight <= 0)
{
_currentWeight = _maxWeight;
}
}
} while (_nodes[_lastChosenNode].Weight < _currentWeight);
if (isLocked)
{
_sLock.Exit(true);
}
return _nodes[_lastChosenNode];
}
/// <summary>
/// 取权重的最大公约数(GreatestCommonDivisor)
/// </summary>
private int GetGcd(List<WeightedNode<T>> nodes)
{
int index = _lastChosenNode;
if (index < 0)
index = 0;
int a = nodes[index].Weight;
if (index >= _nodesCount - 1)
index = -1;
int b = nodes[index + 1].Weight;
while (b != 0)
{
var t = b;
b = a % b;
a = t;
}
return a;
}
/// <summary>
/// 取最大权重值
/// </summary>
private int GetMaxWeight(List<WeightedNode<T>> nodes)
{
int max = nodes.Max(n => n.Weight);
return max;
}
/// <summary>
/// 取所有节点的json字符串的md5值(System.Text.Json的默认配置)
/// </summary>
private string GetMd5(List<WeightedNode<T>> nodes)
{
string json = System.Text.Json.JsonSerializer.Serialize(nodes);
return EncryptHelper.MD5By32(json);
}
}
/// <summary>
/// 权重节点
/// </summary>
public class WeightedNode<T>
{
/// <summary>
/// 节点值
/// </summary>
public T Value { get; set; }
/// <summary>
/// 初始权重
/// </summary>
public int Weight { get; set; }
}
测试
class Program
{
static void Main(string[] args)
{
var dic = new ConcurrentDictionary<string, int>();
var selector = new WeightedRoundRobinHelper<string>(new List<WeightedNode<string>>
{
new WeightedNode<string>(){ Value="1111111111111111", Weight=7},
new WeightedNode<string>(){ Value="2222222222222222", Weight=4},
new WeightedNode<string>(){ Value="3333333333333333", Weight=3},
new WeightedNode<string>(){ Value="4444444444444444", Weight=2},
new WeightedNode<string>(){ Value="5555555555555555", Weight=1},
});
Parallel.For(1, 100, (n) =>
{
var s = selector.GetResult();
var key = $"节点:{s.Value}, 权重:{s.Weight}";
Console.WriteLine(key);
dic.AddOrUpdate(key, 1, (k, v) => v + 1);
});
Console.WriteLine("\r\n");
foreach (var kvp in dic)
{
Console.WriteLine($"{kvp.Key} 总计命中 {kvp.Value} 次");
}
}
}
结果
节点:1111111111111111, 权重:7
节点:2222222222222222, 权重:4
节点:1111111111111111, 权重:7
节点:1111111111111111, 权重:7
节点:2222222222222222, 权重:4
节点:3333333333333333, 权重:3
节点:1111111111111111, 权重:7
节点:4444444444444444, 权重:2
节点:1111111111111111, 权重:7
节点:3333333333333333, 权重:3
节点:2222222222222222, 权重:4
节点:1111111111111111, 权重:7
节点:5555555555555555, 权重:1
节点:4444444444444444, 权重:2
节点:3333333333333333, 权重:3
节点:2222222222222222, 权重:4
节点:2222222222222222, 权重:4
节点:1111111111111111, 权重:7
节点:3333333333333333, 权重:3
节点:1111111111111111, 权重:7
节点:1111111111111111, 权重:7
节点:5555555555555555, 权重:1
节点:1111111111111111, 权重:7
节点:3333333333333333, 权重:3
节点:2222222222222222, 权重:4
节点:3333333333333333, 权重:3
节点:1111111111111111, 权重:7
节点:4444444444444444, 权重:2
节点:2222222222222222, 权重:4
节点:2222222222222222, 权重:4
节点:1111111111111111, 权重:7
节点:4444444444444444, 权重:2
节点:2222222222222222, 权重:4
节点:1111111111111111, 权重:7
节点:4444444444444444, 权重:2
节点:3333333333333333, 权重:3
节点:2222222222222222, 权重:4
节点:1111111111111111, 权重:7
节点:5555555555555555, 权重:1
节点:4444444444444444, 权重:2
节点:3333333333333333, 权重:3
节点:2222222222222222, 权重:4
节点:1111111111111111, 权重:7
节点:1111111111111111, 权重:7
节点:3333333333333333, 权重:3
节点:1111111111111111, 权重:7
节点:2222222222222222, 权重:4
节点:1111111111111111, 权重:7
节点:3333333333333333, 权重:3
节点:1111111111111111, 权重:7
节点:1111111111111111, 权重:7
节点:4444444444444444, 权重:2
节点:1111111111111111, 权重:7
节点:2222222222222222, 权重:4
节点:1111111111111111, 权重:7
节点:5555555555555555, 权重:1
节点:4444444444444444, 权重:2
节点:3333333333333333, 权重:3
节点:1111111111111111, 权重:7
节点:1111111111111111, 权重:7
节点:1111111111111111, 权重:7
节点:3333333333333333, 权重:3
节点:1111111111111111, 权重:7
节点:2222222222222222, 权重:4
节点:1111111111111111, 权重:7
节点:3333333333333333, 权重:3
节点:2222222222222222, 权重:4
节点:1111111111111111, 权重:7
节点:4444444444444444, 权重:2
节点:3333333333333333, 权重:3
节点:2222222222222222, 权重:4
节点:1111111111111111, 权重:7
节点:5555555555555555, 权重:1
节点:4444444444444444, 权重:2
节点:1111111111111111, 权重:7
节点:2222222222222222, 权重:4
节点:1111111111111111, 权重:7
节点:1111111111111111, 权重:7
节点:1111111111111111, 权重:7
节点:2222222222222222, 权重:4
节点:2222222222222222, 权重:4
节点:1111111111111111, 权重:7
节点:3333333333333333, 权重:3
节点:2222222222222222, 权重:4
节点:1111111111111111, 权重:7
节点:3333333333333333, 权重:3
节点:2222222222222222, 权重:4
节点:1111111111111111, 权重:7
节点:2222222222222222, 权重:4
节点:4444444444444444, 权重:2
节点:3333333333333333, 权重:3
节点:2222222222222222, 权重:4
节点:1111111111111111, 权重:7
节点:1111111111111111, 权重:7
节点:1111111111111111, 权重:7
节点:1111111111111111, 权重:7
节点:1111111111111111, 权重:7
节点:5555555555555555, 权重:1
节点:4444444444444444, 权重:2
节点:1111111111111111, 权重:7 总计命中 41 次
节点:3333333333333333, 权重:3 总计命中 17 次
节点:5555555555555555, 权重:1 总计命中 6 次
节点:2222222222222222, 权重:4 总计命中 23 次
节点:4444444444444444, 权重:2 总计命中 12 次
转载请注明出处,谢谢O(∩_∩)O