作者: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